@cmmn/tools 1.9.2 → 1.9.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/bundle/bundle.js CHANGED
@@ -13,17 +13,31 @@ export async function bundle(...options) {
13
13
  stats: options.includes('--stats'),
14
14
  });
15
15
  const configs = configOptions.flatMap(x => new ConfigCreator(x).getConfig());
16
- const contexts = await Promise.all(configs.map(x => esbuild.context(x)));
16
+ const contexts = await Promise.all(configs.map(async x =>
17
+ [x, await esbuild.context(x)]
18
+ ));
17
19
 
18
20
  if (options.includes('--watch')) {
19
- for (let context of contexts) {
20
- await context.watch({});
21
+ for (let [name, context] of contexts) {
22
+ await context.watch();
21
23
  }
22
24
  }else {
23
- for (let context of contexts) {
24
- await context.rebuild();
25
+ const logs = [];
26
+ for (let [config, context] of contexts) {
27
+ const result = await context.rebuild();
28
+ const project = path.relative(process.cwd(), config.absWorkingDir);
29
+ const name = config.entryPoints[0].out;
30
+ let log = logs.find(x => x.project === project && x.name === name);
31
+ if (!log){
32
+ logs.push(log = {project, name});
33
+ }
34
+ for (let [name, value] of Object.entries(result.metafile.outputs)) {
35
+ if (!name.endsWith('js')) continue;
36
+ log[config.format+"."+config.platform] = `${(value.bytes/(2**10)).toFixed(1)} Kb`;
37
+ }
25
38
  await context.dispose();
26
39
  }
40
+ console.table(logs);
27
41
  }
28
42
  }
29
43
 
@@ -1,7 +1,7 @@
1
- import { htmlPlugin } from '@craftamap/esbuild-plugin-html';
2
- import path, {join} from "path";
3
- import {readFileSync} from "node:fs";
1
+ import path from "node:path";
2
+ import fs from "node:fs";
4
3
  import { lessLoader } from 'esbuild-plugin-less';
4
+ import {platform} from "os";
5
5
 
6
6
  /**
7
7
  * @typedef {import(rollup).RollupOptions} RollupOptions
@@ -23,6 +23,7 @@ export class ConfigCreator {
23
23
  * outDir: string,
24
24
  * html: string,
25
25
  * browser: boolean,
26
+ * platform: string,
26
27
  * dedupe: string[],
27
28
  * target: string
28
29
  * inject: string
@@ -42,6 +43,7 @@ export class ConfigCreator {
42
43
  external: [],
43
44
  name: 'index',
44
45
  outDir: 'dist/bundle',
46
+ platform: 'node,browser',
45
47
  ...options
46
48
  };
47
49
  if (options.rootDir)
@@ -52,194 +54,63 @@ export class ConfigCreator {
52
54
  return path.join(this.root, this.options.outDir);
53
55
  }
54
56
 
55
- getOutputFileName(module, minify) {
56
- switch (module) {
57
- case "cjs":
58
- return `[name]${minify ? '.min' : ''}.cjs`;
59
- case "es":
60
- return `[name]${minify ? '.min' : ''}.js`;
61
- default:
62
- return `[name]-${module}${minify ? '.min' : ''}.js`;
63
- }
57
+ get importMaps(){
58
+ return JSON.stringify({
59
+ imports: Object.fromEntries(this.options.external
60
+ .map(key => key.replace('*', '/'))
61
+ .map(key => [key, `/external/${this.options.alias?.[key] ?? key}`]))
62
+ })
63
+ }
64
+ getHtmlPlugin(){
65
+ if (!this.options.html)
66
+ return [];
67
+ return [
68
+ {
69
+ name: 'esbuild-html-plugin',
70
+ setup: (build) => { build.onEnd(async result => {
71
+ if (!result.metafile)
72
+ return;
73
+ const injectStyles = [];
74
+ const injectScripts = [
75
+ `<script type="importmap">${this.importMaps}</script>`
76
+ ];
77
+ for (let [key, value] of Object.entries(result.metafile.outputs)){
78
+ if (value.entryPoint !== this.options.input) continue;
79
+ const file = path.relative(this.outDir, path.join(this.root, key));
80
+ injectScripts.push(`<script type="module" src="/${file}"></script>`)
81
+ if (value.cssBundle) {
82
+ const file = path.relative(this.outDir, path.join(this.root, value.cssBundle));
83
+ injectStyles.push(`<link rel="stylesheet" href="/${file}"></link>`)
84
+ }
85
+ const html = await fs.promises.readFile(path.join(this.root, this.options.html));
86
+ await fs.promises.writeFile(
87
+ path.join(this.outDir, 'index.html'),
88
+ html.toString()
89
+ .replace('</head>', `${injectStyles.map(x => `\t${x}\n`).join('')}</head>`)
90
+ .replace('</body>', `${injectScripts.map(x => `\t${x}\n`).join('')}</body>`)
91
+ );
92
+ }
93
+ }); }
94
+ }
95
+ ];
96
+
64
97
  }
65
- //
66
- // /**
67
- // *
68
- // * @returns {OutputOptions}
69
- // */
70
- // get output() {
71
- // // const output = `${this.options.name ?? 'index'}-${this.options.module}${this.options.minify ? '.min' : ''}.js`;
72
- // return this.options.module.split(',').map(module => ({
73
- // entryFileNames: this.getOutputFileName(module, this.options.minify),
74
- // // file: output,
75
- // dir: this.outDir,
76
- // sourcemap: this.options.minify ? true : 'inline',
77
- // format: module,
78
- // globals: module === 'umd' ? (Array.isArray(this.options.external) ? Object.fromEntries(this.options.external.map(x => [x, x])) : this.options.external) : [],
79
- // assetFileNames: "assets/[name][extname]",
80
- // chunkFileNames: "chunks/[name].js",
81
- // name: this.options.global ?? 'global',
82
- // sourcemapPathTransform: sourceMap => {
83
- // const p = path.relative(this.root, path.resolve(this.outDir, sourceMap));
84
- // return path.join('/', this.options.package, p);
85
- // }
86
- // }));
87
- // }
88
- //
89
- // get html() {
90
- // return html({
91
- // publicPath: '/',
92
- // dir: this.outDir,
93
- // inject: false,
94
- // template: (x) => {
95
- // let inject = (this.options.inject === "json") ? `<script>
96
- // globalThis.assets = ${JSON.stringify(Object.keys(x.bundle.bundle))};
97
- // </script>`: Object.keys(x.bundle.bundle).map(key => {
98
- // if (key.endsWith('css'))
99
- // return `<link rel="stylesheet" href="${this.options.base ?? ''}/${key}" >`;
100
- // if (key.endsWith('js'))
101
- // return `<script type="module" defer src="${this.options.base ?? ''}/${key}"></script>`;
102
- // }).join('\n');
103
- // if (!this.options.minify) {
104
- // const importMaps = Object.fromEntries(this.options.external
105
- // .map(key => key.replace('.*', '/'))
106
- // .map(key => [key, `/external/${this.options.alias?.[key] ?? key}`]));
107
- // inject = `<script type="importmap" >${JSON.stringify({
108
- // imports: importMaps
109
- // })}</script>` + inject;
110
- // }
111
- // if (this.options.base){
112
- // inject = `<base href="${this.options.base}">` + inject;
113
- // }
114
- // const html = fs.readFileSync(path.join(this.root, this.options.html), 'utf8')
115
- // const interpolated = new Function(...Object.keys(this.options), `return \`${html}\`;`)(...Object.values(this.options));
116
- // return interpolated.replace('</head>', inject + '</head>');
117
- // }
118
- // });
119
- // }
120
- //
121
- // get devServer() {
122
- // return serve({
123
- // open: false,
124
- // contentBase: [this.outDir, path.join(this.root, 'assets')],
125
- // port: this.options.port,
126
- // historyApiFallback: true
127
- // });
128
- // }
129
- //
130
- // get livereload() {
131
- // return livereload({
132
- // watch: [this.outDir, path.join(this.root, 'assets'), this.options.html],
133
- // verbose: false, // Disable console output
134
- // // other livereload options
135
- // port: 12345,
136
- // delay: 300,
137
- // })
138
- // }
139
- //
140
- // get visualizer() {
141
- // return visualizer({
142
- // open: true,
143
- // sourcemap: true,
144
- // template: 'treemap',
145
- // brotliSize: true,
146
- //
147
- // filename: path.join(this.outDir, '/stats.html')
148
- // })
149
- // }
150
- //
151
- // get plugins() {
152
- // const result = [
153
- // replace({
154
- // 'process.env.NODE_ENV': JSON.stringify(this.options.minify ? 'production' : 'development'),
155
- // preventAssignment: true
156
- // }),
157
- // ...Styles(this),
158
- // commonjs({
159
- // requireReturnsDefault: "namespace",
160
- // transformMixedEsModules: true,
161
- // defaultIsModuleExports: true,
162
- // }),
163
- // nodeResolve({
164
- // browser: this.options.browser,
165
- // dedupe: this.options.dedupe || [],
166
- // preferBuiltins: !this.options.browser
167
- // }),
168
- // sourcemaps(),
169
- // builtins(),
170
- // /*this.options.styles === 'modules' ? postCSS({
171
- // mode: [
172
- // "inject",
173
- // {container: "head", prepend: true, attributes: {id: "global"}},
174
- // ],
175
- // plugins: [
176
- // flexbugs,
177
- // ],
178
- // modules: {
179
- // root: ''
180
- // },
181
- // namedExports: false,
182
- // autoModules: true,
183
- // }) : */
184
- // Styles(this),
185
- //
186
- // string({
187
- // include: /\.(html|svg|less)$/,
188
- // exclude: /\.module\.css/
189
- // }),
190
- // json(),
191
- //
192
- // ];
193
- // if (this.options.alias) {
194
- // result.unshift(alias({
195
- // entries: Object.entries(this.options.alias).map(([key, value]) => ({
196
- // find: key,
197
- // replacement: value.replace('<root>', this.root)
198
- // }))
199
- // }));
200
- // }
201
- // if (this.options.minify && this.options.mount){
202
- // const toCopy = Object.entries(this.options.mount).map(([to, from]) => {
203
- // return {src: from + '/*', dest: join(this.outDir, to)}
204
- // });
205
- // result.push(copy({
206
- // targets: toCopy
207
- // }));
208
- // }
209
- // if (this.options.html || this.options.input.endsWith('.html')) {
210
- // result.push(this.html);
211
- // result.push(watcher([path.join(this.root, this.options.html)]))
212
- // }
213
- // if (this.options.stats) {
214
- // result.push(this.visualizer);
215
- // }
216
- // if (this.options.minify) {
217
- // result.push(terser({
218
- // module: true,
219
- // ecma: 2020,
220
- // compress: true,
221
- // keep_classnames: false,
222
- // keep_fnames: false,
223
- // mangle: true,
224
- // output: {
225
- // comments: false
226
- // }
227
- // }));
228
- // }
229
- // if (this.options.devServer && this.options.port) {
230
- // result.push(this.devServer, this.livereload);
231
- // }
232
- // return result;
233
- // }
234
- //
235
- // getExternals() {
236
- // if (!this.options.external)
237
- // return [];
238
- // if (Array.isArray(this.options.external))
239
- // return this.options.external.map(s => new RegExp(s));
240
- // return Object.keys(this.options.external).map(s => new RegExp(s));
241
- // }
242
98
 
99
+ get platforms(){
100
+ return this.options.platform.split(',');
101
+ }
102
+ get modules(){
103
+ return this.options.module.split(',');
104
+ }
105
+ getOutExtension(format, platform){
106
+ const ext = (this.options.minify ? '.min' : '') + {
107
+ es: '.js',
108
+ cjs: '.cjs'
109
+ }[format];
110
+ if (this.platforms.length == 1)
111
+ return ext;
112
+ return "."+platform+ext;
113
+ }
243
114
  /**
244
115
  * @returns {RollupOptions[]}
245
116
  */
@@ -247,13 +118,13 @@ export class ConfigCreator {
247
118
  if (this.options.external && typeof this.options.external === "string")
248
119
  this.options.external = [this.options.external]
249
120
  console.log(this.options.name, this.options);
250
- return this.options.module.split(",").map(format => ({
121
+ return this.modules.flatMap(format => this.platforms.map(platform => ({
251
122
  entryPoints: [
252
123
  { out: this.options.name, in: this.options.input }
253
124
  ],
254
125
  bundle: true,
255
126
  minify: this.options.minify,
256
- sourcemap: true,
127
+ sourcemap: this.options.minify ? false : 'external',
257
128
  target: ['chrome88', 'safari14', 'firefox88'],
258
129
  outdir: 'dist/bundle',
259
130
  metafile: true,
@@ -263,14 +134,11 @@ export class ConfigCreator {
263
134
  es: 'esm'
264
135
  })[format] ?? format,
265
136
  outExtension: {
266
- '.js': (this.options.minify ? '.min' : '') + {
267
- es: '.js',
268
- cjs: '.cjs'
269
- }[format]
137
+ '.js': this.getOutExtension(format, platform)
270
138
  },
271
- platform: this.options.browser ? 'browser': 'node',
139
+ platform: platform,
272
140
  tsconfig: 'tsconfig.json',
273
- external: ["*.woff2", "*.woff", ...this.options.external.map(x => x+"*")],
141
+ external: ["*.woff2", "*.woff", ...this.options.external],
274
142
  define: {
275
143
  'process.env.NODE_ENV': '"production"'
276
144
  },
@@ -278,63 +146,8 @@ export class ConfigCreator {
278
146
  alias: this.options.alias,
279
147
  plugins: [
280
148
  lessLoader(),
281
- ...(this.options.html ? [htmlPlugin({
282
- files: [{
283
- entryPoints: [this.options.input],
284
- filename: 'index.html',
285
- scriptLoading: 'module',
286
- htmlTemplate: readFileSync(this.options.html).toString().replace('</head>', `<script type="importmap">
287
- ${JSON.stringify({
288
- imports: Object.fromEntries(this.options.external
289
- .map(key => key.replace('*', '/'))
290
- .map(key => [key, `/external/${this.options.alias?.[key] ?? key}`]))
291
- })}
292
- </script>`),
293
- // if (!this.options.minify) {
294
- // const importMaps = Object.fromEntries(this.options.external
295
- // .map(key => key.replace('.*', '/'))
296
- // .map(key => [key, `/external/${this.options.alias?.[key] ?? key}`]));
297
- // inject = `<script type="importmap" >${JSON.stringify({
298
- // imports: importMaps
299
- // })}</script>` + inject;
300
- // }
301
- // extraScripts: [
302
- // `data:text/javascript,new EventSource('/esbuild').addEventListener('change', () => location.reload())`,
303
- // ],
304
- define: {
305
- }
306
- }]
307
- })] : []),
149
+ ...this.getHtmlPlugin(),
308
150
  ],
309
-
310
- // output: this.output,
311
- // external: (this.options.minify && this.options.browser) ? [] : this.getExternals(),
312
- // manualChunks: this.options.chunks,
313
- // onwarn(warning) {
314
- // switch (warning.code) {
315
- // case 'CIRCULAR_DEPENDENCY':
316
- // return;
317
- // case 'THIS_IS_UNDEFINED':
318
- // console.log(`${warning.message} at`);
319
- // console.log(`\t${warning.id}`);
320
- // break;
321
- // case 'PLUGIN_WARNING':
322
- // console.log(`${warning.message} at`);
323
- // console.log(`\t${warning.id}`);
324
- // break;
325
- // default:
326
- // console.warn(`\t${warning.code}(!) ${warning.message}`)
327
- // }
328
- //
329
- // },
330
- // plugins: this.plugins,
331
- // preserveEntrySignatures: true,
332
- // treeshake: this.options.minify ? "recommended" : "safest",
333
- // watch: {
334
- // buildDelay: 300,
335
- // clearScreen: false,
336
- // exclude: this.getExternals().concat(path.join(this.root, this.outDir)),
337
- // }
338
- }));
151
+ })));
339
152
  }
340
153
  }
@@ -16,19 +16,30 @@ function getPackageConfigs(rootDir, options, name = null) {
16
16
  return [];
17
17
  const results = [];
18
18
  const pkg = JSON.parse(fs.readFileSync(pckPath));
19
- if (name) {
20
- results.push(getProjectConfig(rootDir, pkg.cmmn[name], {
21
- ...options,
22
- name,
23
- package: pkg.name,
19
+ if (pkg.workspaces){
20
+ const dirs = pkg.workspaces.flatMap(pkg => fg.sync([pkg], {
21
+ absolute: true,
22
+ globstar: true,
23
+ onlyDirectories: true,
24
+ cwd: rootDir
24
25
  }));
25
- } else {
26
- for (let name in pkg.cmmn) {
26
+ dirs.forEach(d => results.push(...getPackageConfigs(d, options, name)));
27
+ }
28
+ if (pkg.cmmn) {
29
+ if (name) {
27
30
  results.push(getProjectConfig(rootDir, pkg.cmmn[name], {
28
31
  ...options,
29
32
  name,
30
33
  package: pkg.name,
31
34
  }));
35
+ } else {
36
+ for (let name in pkg.cmmn) {
37
+ results.push(getProjectConfig(rootDir, pkg.cmmn[name], {
38
+ ...options,
39
+ name,
40
+ package: pkg.name,
41
+ }));
42
+ }
32
43
  }
33
44
  }
34
45
  return results;
@@ -38,6 +38,8 @@ function createProgram(rootNames, options, host, oldProgram, configFileParsingDi
38
38
  options.declarationDir = resolve(options.configFilePath, '../dist/typings');
39
39
  options.baseUrl = resolve(options.configFilePath, '../');
40
40
  options.tsBuildInfoFile = resolve(options.configFilePath, '../dist/ts.buildinfo');
41
+ // options.excludeDirectories.baseUrl = options.baseUrl;
42
+ // options.includeDirectories.baseUrl = options.baseUrl;
41
43
  if (!cleanedBaseDirs.has(options.baseUrl)){
42
44
  fs.rmSync(options.outDir, {recursive: true, force: true});
43
45
  fs.rmSync(options.declarationDir, {recursive: true, force: true});
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cmmn/tools",
3
- "version": "1.9.2",
3
+ "version": "1.9.4",
4
4
  "description": "Compilation, bundling, code generator, testing.",
5
5
  "main": "dist/rollup.config.js",
6
6
  "type": "module",
@@ -41,7 +41,6 @@
41
41
  "test/*"
42
42
  ],
43
43
  "dependencies": {
44
- "@craftamap/esbuild-plugin-html": "0.6.1",
45
44
  "@jest/globals": "27.x.x",
46
45
  "@swc/jest": "0.2.17",
47
46
  "@testdeck/jest": "0.2.0",
@@ -59,10 +58,9 @@
59
58
  "less": "^4",
60
59
  "live-server": "1.2.2",
61
60
  "sinon": "10.x.x",
62
- "ts-jest": "29.x.x",
63
- "unique-slug": "*"
61
+ "ts-jest": "29.x.x"
64
62
  },
65
63
  "author": "",
66
64
  "license": "ISC",
67
- "gitHead": "2b9d0cf9093d3cde17f2d222604866a2c253ebdc"
65
+ "gitHead": "1602adb5285c0b8a7bd52d5a5d32860cdad4a434"
68
66
  }
package/serve/serve.js CHANGED
@@ -17,10 +17,11 @@ export function serve(...options) {
17
17
  file: 'index.html',
18
18
  port: process.env.PORT ? (+process.env.PORT + i) : x.port,
19
19
  open: false,
20
+ watch: configs.map(x => path.join(x.rootDir, x.outDir ?? 'dist/bundle')).join(','),
20
21
  mount: x.mount && Object.entries(x.mount)
21
- .map(([from, to]) => [from, path.resolve(x.rootDir, to)])
22
- .concat(configs.map(x => [`/external/${x.package}`,
23
- path.join(x.rootDir, x.outDir ?? `dist/bundle/${x.name}.js`)])),
22
+ .map(([from, to]) => [from, path.resolve(x.rootDir, to)]),
23
+ // .concat(configs.map(x => [`/external/${x.package}`,
24
+ // path.join(x.rootDir, x.outDir ?? `dist/bundle/${x.name}.js`)])),
24
25
  proxy: Object.entries(x.proxy ?? {}),
25
26
  middleware: [resolveESModule(x.rootDir, configs)].filter(x => x)
26
27
  });
@@ -36,6 +37,16 @@ function getModuleName(path) {
36
37
 
37
38
  const mappingCache = {};
38
39
 
40
+ async function resolveModule(module, root){
41
+ const conditions = ['browser', 'main', 'module', 'import', 'node', 'default'];
42
+ for (let condition of conditions) {
43
+ try {
44
+ return moduleResolve(module, root, new Set([condition]));
45
+ }catch (e){
46
+ }
47
+ }
48
+ throw new Error(`Failed resolve ${module} from ${root}`);
49
+ }
39
50
  // for resolve modules and files inside modules
40
51
  async function getFileName(moduleName, root) {
41
52
  // console.log(moduleName, root);
@@ -44,21 +55,22 @@ async function getFileName(moduleName, root) {
44
55
  let file;
45
56
  if (moduleName.match('\.[cm]?js')) {
46
57
  const module = moduleName.match(/^(@[^/]+\/)?[^/]+/)[0];
47
- const main = (await moduleResolve(module, root, new Set(['module', 'import', 'browser', 'main', 'node'])));
58
+ const main = await resolveModule(module, root);
48
59
  const file = main.href.replace(new RegExp('node_modules/' + module + '.*$'), 'node_modules/' + moduleName);
49
- console.log(file)
50
60
  return mappingCache[moduleName] = file;
51
61
  } else {
52
- const file = (await moduleResolve(moduleName, root, new Set(['module', 'import', 'browser', 'main', 'node'])));
62
+ const file = await resolveModule(moduleName, root);
53
63
  return mappingCache[moduleName] = file.href;
54
64
  }
55
65
  }
56
66
  const resolveESModule = (rootDir, configs) => async function (req, res, next) {
57
67
  const name = getModuleName(req.url);
58
- if (!name)
59
- return next();
60
- if (configs.some(x => x.package === name))
68
+ if (!name) {
69
+ console.log(`skip ${req.url}`)
61
70
  return next();
71
+ }
72
+ // if (configs.some(x => x.package === name))
73
+ // return next();
62
74
  const referer = req.headers.referer?.substring(req.headers.origin.length);
63
75
  const refererModule = referer && getModuleName(referer);
64
76
  const root = refererModule
@@ -67,7 +79,7 @@ const resolveESModule = (rootDir, configs) => async function (req, res, next) {
67
79
  try {
68
80
  const file = uri2path(await getFileName(name, root));
69
81
  var stat = fs.statSync(file);
70
-
82
+ console.info(`Resolve ${name} to ${file}`)
71
83
  res.writeHead(200, {
72
84
  'Content-Type': 'application/javascript',
73
85
  'Content-Length': stat.size