add postcss, fix export names

This commit is contained in:
Sebastian 2023-05-05 08:34:21 -03:00
parent 5e1f450a20
commit 6340cc5454
No known key found for this signature in database
GPG Key ID: 173909D1A5F66069
10 changed files with 1967 additions and 421 deletions

View File

@ -15,34 +15,38 @@
GNU Taler; see the file COPYING. If not, see <http://www.gnu.org/licenses/>
*/
import esbuild from 'esbuild'
import path from "path"
import fs from "fs"
import esbuild from "esbuild";
import path from "path";
import fs from "fs";
// eslint-disable-next-line no-undef
const BASE = process.cwd()
const BASE = process.cwd();
let GIT_ROOT = BASE
while (!fs.existsSync(path.join(GIT_ROOT, '.git')) && GIT_ROOT !== '/') {
GIT_ROOT = path.join(GIT_ROOT, '../')
let GIT_ROOT = BASE;
while (!fs.existsSync(path.join(GIT_ROOT, ".git")) && GIT_ROOT !== "/") {
GIT_ROOT = path.join(GIT_ROOT, "../");
}
if (GIT_ROOT === '/') {
if (GIT_ROOT === "/") {
// eslint-disable-next-line no-undef
console.log("not found")
console.log("not found");
// eslint-disable-next-line no-undef
process.exit(1);
}
const GIT_HASH = GIT_ROOT === '/' ? undefined : git_hash()
const GIT_HASH = GIT_ROOT === "/" ? undefined : git_hash();
let _package = JSON.parse(fs.readFileSync(path.join(BASE, 'package.json')));
let _package = JSON.parse(fs.readFileSync(path.join(BASE, "package.json")));
function git_hash() {
const rev = fs.readFileSync(path.join(GIT_ROOT, '.git', 'HEAD')).toString().trim().split(/.*[: ]/).slice(-1)[0];
if (rev.indexOf('/') === -1) {
const rev = fs
.readFileSync(path.join(GIT_ROOT, ".git", "HEAD"))
.toString()
.trim()
.split(/.*[: ]/)
.slice(-1)[0];
if (rev.indexOf("/") === -1) {
return rev;
} else {
return fs.readFileSync(path.join(GIT_ROOT, '.git', rev)).toString().trim();
return fs.readFileSync(path.join(GIT_ROOT, ".git", rev)).toString().trim();
}
}
@ -50,20 +54,18 @@ const buildConfigBase = {
outdir: "lib",
bundle: true,
minify: false,
target: [
'es6'
],
target: ["es2021"],
loader: {
'.key': 'text',
'.crt': 'text',
'.html': 'text',
".key": "text",
".crt": "text",
".html": "text",
},
sourcemap: true,
define: {
'__VERSION__': `"${_package.version}"`,
'__GIT_HASH__': `"${GIT_HASH}"`,
__VERSION__: `"${_package.version}"`,
__GIT_HASH__: `"${GIT_HASH}"`,
},
}
};
/**
* Build time libraries, under node runtime
@ -72,36 +74,52 @@ const buildConfigBuild = {
...buildConfigBase,
entryPoints: ["src/index.build.ts"],
outExtension: {
'.js': '.mjs'
".js": ".mjs",
},
format: 'esm',
platform: 'node',
format: "esm",
platform: "node",
external: ["esbuild"],
// https://github.com/evanw/esbuild/issues/1921
// How to fix "Dynamic require of "os" is not supported"
// esbuild cannot convert external "static" commonjs require statements to static esm imports
banner: {
banner: {
js: `
import { fileURLToPath } from 'url';
import { createRequire as topLevelCreateRequire } from 'module';
const require = topLevelCreateRequire(import.meta.url);
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
`
`,
},
};
/**
* Development libraries, under node runtime
*/
const buildConfigTesting = {
...buildConfigBase,
entryPoints: ["src/index.testing.ts"],
outExtension: {
".js": ".mjs",
},
format: "esm",
platform: "browser",
external: ["preact", "@gnu-taler/taler-util", "jed", "swr", "axios"],
jsxFactory: "h",
jsxFragment: "Fragment",
};
/**
* Testing libraries, under node runtime
*/
const buildConfigNode = {
...buildConfigBase,
entryPoints: ["src/index.node.ts", "src/cli.ts"],
outExtension: {
'.js': '.cjs'
".js": ".cjs",
},
format: 'cjs',
platform: 'node',
format: "cjs",
platform: "node",
external: ["preact"],
};
@ -110,26 +128,33 @@ const buildConfigNode = {
*/
const buildConfigBrowser = {
...buildConfigBase,
entryPoints: ["src/tests/mock.ts", "src/tests/swr.ts", "src/index.browser.ts", "src/live-reload.ts", 'src/stories.tsx'],
entryPoints: [
"src/tests/mock.ts",
"src/tests/swr.ts",
"src/index.browser.ts",
"src/live-reload.ts",
"src/stories.tsx",
],
outExtension: {
'.js': '.mjs'
".js": ".mjs",
},
format: 'esm',
platform: 'browser',
external: ["preact", "@gnu-taler/taler-util", "jed","swr","axios"],
jsxFactory: 'h',
jsxFragment: 'Fragment',
format: "esm",
platform: "browser",
external: ["preact", "@gnu-taler/taler-util", "jed", "swr", "axios"],
jsxFactory: "h",
jsxFragment: "Fragment",
};
[buildConfigNode, buildConfigBrowser, buildConfigBuild].forEach((config) => {
esbuild
.build(config)
.catch((e) => {
// eslint-disable-next-line no-undef
console.log(e)
// eslint-disable-next-line no-undef
process.exit(1)
});
})
[
buildConfigNode,
buildConfigBrowser,
buildConfigBuild,
buildConfigTesting,
].forEach((config) => {
esbuild.build(config).catch((e) => {
// eslint-disable-next-line no-undef
console.log(e);
// eslint-disable-next-line no-undef
process.exit(1);
});
});

View File

@ -9,25 +9,21 @@
"license": "AGPL-3.0-or-later",
"private": false,
"exports": {
"./lib/tests/swr": {
"types": "./lib/tests/swr.js",
"default": "./lib/tests/swr.mjs"
},
"./lib/tests/mock": {
"types": "./lib/tests/mock.js",
"default": "./lib/tests/mock.mjs"
},
"./lib/index.browser": {
"./browser": {
"types": "./lib/index.browser.js",
"default": "./lib/index.browser.mjs"
},
"./lib/index.build": {
"./build": {
"types": "./lib/index.build.js",
"default": "./lib/index.build.mjs"
},
"./lib/index.node": {
"./node": {
"types": "./lib/index.node.js",
"default": "./lib/index.node.cjs"
},
"./testing": {
"types": "./lib/index.testing.js",
"default": "./lib/index.testing.mjs"
}
},
"scripts": {
@ -42,21 +38,31 @@
"@types/node": "^18.11.17",
"@types/web": "^0.0.82",
"@types/ws": "^8.5.3",
"autoprefixer": "^10.4.14",
"axios": "^1.2.2",
"chokidar": "^3.5.3",
"esbuild": "^0.17.7",
"express": "^4.18.2",
"postcss": "^8.4.23",
"postcss-load-config": "^4.0.1",
"preact": "10.11.3",
"preact-render-to-string": "^5.2.6",
"prettier": "^2.5.1",
"rimraf": "^3.0.2",
"sass": "1.56.1",
"swr": "2.0.3",
"tslib": "^2.4.0",
"sass": "1.56.1",
"typescript": "^4.9.4",
"ws": "7.4.5"
},
"dependencies": {
"@types/chrome": "0.0.197"
"@babel/core": "7.18.9",
"@babel/helper-compilation-targets": "7.18.9",
"@linaria/babel-preset": "3.0.0-beta.23",
"@linaria/core": "3.0.0-beta.22",
"@linaria/esbuild": "3.0.0-beta.22",
"@linaria/react": "3.0.0-beta.22",
"@types/chrome": "0.0.197",
"tailwindcss": "^3.3.2"
}
}
}

View File

@ -36,7 +36,6 @@ walletCli
return serve({
folder: args.serve.folder || "./dist",
port: args.serve.port || 8000,
development: args.serve.development,
});
});

View File

@ -5,5 +5,4 @@ export * from "./utils/http-impl.sw.js";
export * from "./utils/observable.js";
export * from "./context/index.js";
export * from "./components/index.js";
export * as tests from "./tests/index.js";
export { renderStories, parseGroupImport } from "./stories.js";

View File

@ -1,15 +1,14 @@
import esbuild from "esbuild";
import path from "path";
import esbuild, { PluginBuild } from "esbuild";
// import linaria from "@linaria/esbuild";
import fs from "fs";
import path from "path";
import postcss from "postcss";
import sass from "sass";
import { PluginBuild } from "esbuild";
import postcssrc from "postcss-load-config";
// this should give us the current directory where
// the project is being built
const BASE = process.cwd();
const distProd = path.join(BASE, "dist", "prod");
const distDev = path.join(BASE, "dist", "dev");
const sourceDir = path.join(BASE, "src");
const preact = path.join(
BASE,
@ -32,11 +31,10 @@ const preactCompatPlugin: esbuild.Plugin = {
},
};
export function getFilesInSource(regex: RegExp): string[] {
return getFilesInDirectory(sourceDir, regex);
}
function getFilesInDirectory(startPath: string, regex: RegExp): string[] {
export function getFilesInDirectory(
startPath: string,
regex?: RegExp,
): string[] {
if (!fs.existsSync(startPath)) {
return [];
}
@ -49,7 +47,7 @@ function getFilesInDirectory(startPath: string, regex: RegExp): string[] {
if (stat.isDirectory()) {
return getFilesInDirectory(filename, regex);
}
if (regex.test(filename)) {
if (!regex || regex.test(filename)) {
return [filename];
}
return [];
@ -108,7 +106,7 @@ function copyFilesPlugin(files: Array<string>) {
const DEFAULT_SASS_FILTER = /\.(s[ac]ss|css)$/;
const buildSassPlugin: esbuild.Plugin = {
const sassPlugin: esbuild.Plugin = {
name: "custom-build-sass",
setup(build) {
build.onLoad({ filter: DEFAULT_SASS_FILTER }, ({ path: file }) => {
@ -124,7 +122,42 @@ const buildSassPlugin: esbuild.Plugin = {
},
};
const buildConfig: esbuild.BuildOptions = {
const postCssPlugin: esbuild.Plugin = {
name: "custom-build-postcss",
setup(build) {
build.onLoad({ filter: DEFAULT_SASS_FILTER }, async ({ path: file }) => {
const resolveDir = path.dirname(file);
const sourceBuffer = fs.readFileSync(file);
const source = sourceBuffer.toString("utf-8");
const postCssConfig = await postcssrc();
postCssConfig.options.from = file;
const { css: contents } = await postcss(postCssConfig.plugins).process(
source,
postCssConfig.options,
);
return {
resolveDir,
loader: "css",
contents,
};
});
},
};
function linariaPlugin() {
// const linariaCssPlugin: esbuild.Plugin = linaria.default({
// babelOptions: {
// babelrc: false,
// configFile: "./babel.config-linaria.json",
// },
// sourceMap: true,
// });
// return linariaCssPlugin;
}
const defaultEsBuildConfig: esbuild.BuildOptions = {
bundle: true,
minify: false,
loader: {
@ -146,43 +179,71 @@ const buildConfig: esbuild.BuildOptions = {
__VERSION__: `"${_package.version}"`,
__GIT_HASH__: `"${GIT_HASH}"`,
},
plugins: [
preactCompatPlugin,
copyFilesPlugin(["./src/index.html"]),
buildSassPlugin,
],
};
export interface BuildParams {
source: {
assets: string[];
js: string[];
};
destination: string;
css: "sass" | "postcss"; // | "linaria";
}
export function computeConfig(params: BuildParams) {
const plugins: Array<esbuild.Plugin> = [
preactCompatPlugin,
copyFilesPlugin(params.source.assets),
];
switch (params.css) {
case "sass": {
plugins.push(sassPlugin);
break;
}
case "postcss": {
plugins.push(postCssPlugin);
break;
}
// case "linaria": {
// plugins.push(linariaPlugin());
// break;
// }
default: {
const cssType: never = params.css;
throw Error(`not supported: ${cssType}`);
}
}
return {
...defaultEsBuildConfig,
entryPoints: params.source.js,
outdir: params.destination,
plugins,
};
}
/**
* Build sources for prod environment
*/
export function buildProd(entryPoints: string[]) {
return esbuild.build({
...buildConfig,
entryPoints,
outdir: distProd,
});
export function build(config: BuildParams) {
return esbuild.build(computeConfig(config));
}
/**
* Build sources for dev environment
*/
function buildDev(entryPoints: string[]): Promise<esbuild.BuildResult> {
return esbuild.build({
...buildConfig,
entryPoints,
outdir: distDev,
});
}
const LIVE_RELOAD_SCRIPT =
"./node_modules/@gnu-taler/web-util/lib/live-reload.mjs";
/**
* Do startup for development environment
*/
export function initializeDev(
entryPoints: string[],
config: BuildParams,
): () => Promise<esbuild.BuildResult> {
buildConfig.inject = [
"./node_modules/@gnu-taler/web-util/lib/live-reload.mjs",
];
return () => buildDev(entryPoints);
function buildDevelopment() {
const result = computeConfig(config);
result.inject = [LIVE_RELOAD_SCRIPT];
return esbuild.build(result);
}
return buildDevelopment;
}

View File

@ -0,0 +1,3 @@
export * from "./tests/hook.js";
export * from "./tests/swr.js";
export * from "./tests/mock.js";

View File

@ -1 +0,0 @@
export default {};

View File

@ -21,7 +21,6 @@ const logger = new Logger("serve.ts");
const PATHS = {
WS: "/ws",
NOTIFY: "/notify",
EXAMPLE: "/examples",
APP: "/app",
};
@ -30,101 +29,97 @@ export async function serve(opts: {
folder: string;
port: number;
source?: string;
development?: boolean;
examplesLocationJs?: string;
examplesLocationCss?: string;
onUpdate?: () => Promise<void>;
onSourceUpdate?: () => Promise<void>;
}): Promise<void> {
const app = express();
app.use(PATHS.APP, express.static(opts.folder));
const servers = [
http.createServer(app),
https.createServer(httpServerOptions, app),
];
logger.info(` ${PATHS.APP}: application`);
logger.info(` ${PATHS.EXAMPLE}: examples`);
logger.info(` ${PATHS.WS}: websocket`);
logger.info(` ${PATHS.NOTIFY}: broadcast`);
if (opts.development) {
const wss = new WebSocket.Server({ noServer: true });
const httpServer = http.createServer(app);
const httpPort = opts.port;
const httpsServer = https.createServer(httpServerOptions, app);
const httpsPort = opts.port + 1;
const servers = [httpServer, httpsServer];
wss.on("connection", function connection(ws) {
ws.send("welcome");
});
logger.info(`Dev server. Endpoints:`);
logger.info(` ${PATHS.APP}: where root application can be tested`);
logger.info(` ${PATHS.EXAMPLE}: where examples can be found and browse`);
logger.info(` ${PATHS.WS}: websocket for live reloading`);
servers.forEach(function addWSHandler(server) {
server.on("upgrade", function upgrade(request, socket, head) {
const { pathname } = parse(request.url || "");
if (pathname === PATHS.WS) {
wss.handleUpgrade(request, socket, head, function done(ws) {
wss.emit("connection", ws, request);
});
} else {
socket.destroy();
}
});
});
const wss = new WebSocket.Server({ noServer: true });
const sendToAllClients = function (data: object): void {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(data));
}
});
};
const watchingFolder = opts.source ?? opts.folder;
logger.info(`watching ${watchingFolder} for change`);
wss.on("connection", function connection(ws) {
ws.send("welcome");
});
chokidar.watch(watchingFolder).on("change", (path, stats) => {
logger.info(`changed ${path}`);
if (opts.onUpdate) {
sendToAllClients({ type: "file-updated-start", data: { path } });
opts
.onUpdate()
.then((result) => {
sendToAllClients({
type: "file-updated-done",
data: { path, result },
});
})
.catch((error) => {
sendToAllClients({
type: "file-updated-failed",
data: { path, error },
});
});
servers.forEach(function addWSHandler(server) {
server.on("upgrade", function upgrade(request, socket, head) {
const { pathname } = parse(request.url || "");
if (pathname === PATHS.WS) {
wss.handleUpgrade(request, socket, head, function done(ws) {
wss.emit("connection", ws, request);
});
} else {
sendToAllClients({ type: "file-change", data: { path } });
socket.destroy();
}
});
});
if (opts.onUpdate) opts.onUpdate();
app.get(PATHS.EXAMPLE, function (req: any, res: any) {
res.set("Content-Type", "text/html");
res.send(
storiesHtml
.replace(
"__EXAMPLES_JS_FILE_LOCATION__",
opts.examplesLocationJs ?? `.${PATHS.APP}/stories.js`,
)
.replace(
"__EXAMPLES_CSS_FILE_LOCATION__",
opts.examplesLocationCss ?? `.${PATHS.APP}/stories.css`,
),
);
const sendToAllClients = function (data: object): void {
wss.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(JSON.stringify(data));
}
});
};
const watchingFolder = opts.source ?? opts.folder;
logger.info(`watching ${watchingFolder} for changes`);
app.get(PATHS.NOTIFY, function (req: any, res: any) {
res.send("ok");
});
chokidar.watch(watchingFolder).on("change", (path, stats) => {
logger.info(`changed: ${path}`);
servers.forEach(function startServer(server, index) {
logger.info(`serving ${opts.folder} on ${opts.port + index}`);
server.listen(opts.port + index);
});
}
if (opts.onSourceUpdate) {
sendToAllClients({ type: "file-updated-start", data: { path } });
opts
.onSourceUpdate()
.then((result) => {
sendToAllClients({
type: "file-updated-done",
data: { path, result },
});
})
.catch((error) => {
sendToAllClients({
type: "file-updated-failed",
data: { path, error },
});
});
} else {
sendToAllClients({ type: "file-change", data: { path } });
}
});
if (opts.onSourceUpdate) opts.onSourceUpdate();
app.get(PATHS.EXAMPLE, function (req: any, res: any) {
res.set("Content-Type", "text/html");
res.send(
storiesHtml
.replace(
"__EXAMPLES_JS_FILE_LOCATION__",
opts.examplesLocationJs ?? `.${PATHS.APP}/stories.js`,
)
.replace(
"__EXAMPLES_CSS_FILE_LOCATION__",
opts.examplesLocationCss ?? `.${PATHS.APP}/stories.css`,
),
);
});
logger.info(`Serving ${opts.folder} on ${httpPort}: plain HTTP`);
httpServer.listen(httpPort);
logger.info(`Serving ${opts.folder} on ${httpsPort}: HTTP + TLS`);
httpsServer.listen(httpsPort);
}

View File

@ -1,2 +0,0 @@
export * from "./hook.js";
// export * from "./axios.js"

File diff suppressed because it is too large Load Diff