jiek 2.2.1 → 2.2.3

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.
@@ -7,9 +7,9 @@ var commander = require('commander');
7
7
  var jsYaml = require('js-yaml');
8
8
  var getWorkspaceDir = require('@jiek/utils/getWorkspaceDir');
9
9
  var process$1 = require('node:process');
10
- var prompts = require('@inquirer/prompts');
11
10
  var cliProgress = require('cli-progress');
12
11
  var execa = require('execa');
12
+ var prompts = require('@inquirer/prompts');
13
13
  var Koa = require('koa');
14
14
 
15
15
  var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
@@ -22,8 +22,7 @@ var Koa__default = /*#__PURE__*/_interopDefault(Koa);
22
22
 
23
23
  let root;
24
24
  function getRoot() {
25
- if (root)
26
- return root;
25
+ if (root) return root;
27
26
  const rootOption = process.env.JIEK_ROOT;
28
27
  root = rootOption ? path__default.default.isAbsolute(rootOption) ? rootOption : path__default.default.resolve(process.cwd(), rootOption) : void 0;
29
28
  return root;
@@ -32,8 +31,7 @@ function getRoot() {
32
31
  let wd;
33
32
  let notWorkspace$1 = false;
34
33
  function getWD() {
35
- if (wd)
36
- return { wd, notWorkspace: notWorkspace$1 };
34
+ if (wd) return { wd, notWorkspace: notWorkspace$1 };
37
35
  const root = getRoot();
38
36
  if (root !== void 0) {
39
37
  const isWorkspace = getWorkspaceDir.isWorkspaceDir(root, type$1);
@@ -120,7 +118,7 @@ async function getSelectedProjectsGraph(filter = commander.program.getOptionValu
120
118
 
121
119
  var name = "jiek";
122
120
  var type = "module";
123
- var version = "2.2.0";
121
+ var version = "2.2.2";
124
122
  var description$1 = "A lightweight toolkit for compiling and managing libraries based on `package.json` metadata and suitable for `Monorepo`.";
125
123
  var author = "YiJie <yijie4188@gmail.com>";
126
124
  var homepage = "https://github.com/NWYLZW/jiek/tree/master/packages/jiek#readme";
@@ -151,7 +149,11 @@ var exports$1 = {
151
149
  "./rollup": "./src/rollup/index.ts"
152
150
  };
153
151
  var imports = {
154
- "#~/*": "./src/*"
152
+ "#~/*": [
153
+ "./src/*",
154
+ "./src/*/index.ts",
155
+ "./src/*/index.tsx"
156
+ ]
155
157
  };
156
158
  var bin = {
157
159
  jiek: "bin/jiek.js",
@@ -182,7 +184,7 @@ var peerDependencies = {
182
184
  "rollup-plugin-postcss": "^4.0.2",
183
185
  "rollup-plugin-swc3": "^0.12.1",
184
186
  typescript: "^4.0.0||^5.0.0",
185
- "vite-bundle-analyzer": "^0.15.2"
187
+ "vite-bundle-analyzer": "0.16.0-beta.1"
186
188
  };
187
189
  var dependencies = {
188
190
  "@inquirer/prompts": "^7.1.0",
@@ -213,6 +215,7 @@ var devDependencies = {
213
215
  "@types/js-yaml": "^4.0.9",
214
216
  "@types/koa": "^2.15.0",
215
217
  "@types/micromatch": "^4.0.6",
218
+ "@types/react": "^18.3.14",
216
219
  "esbuild-register": "^3.5.0",
217
220
  micromatch: "^4.0.5",
218
221
  "node-sass": "^9.0.0",
@@ -220,7 +223,7 @@ var devDependencies = {
220
223
  "rollup-plugin-esbuild": "^6.1.0",
221
224
  "rollup-plugin-postcss": "^4.0.2",
222
225
  "rollup-plugin-swc3": "^0.12.1",
223
- "vite-bundle-analyzer": "^0.15.2"
226
+ "vite-bundle-analyzer": "0.16.0-beta.1"
224
227
  };
225
228
  var pkg = {
226
229
  name: name,
@@ -266,6 +269,208 @@ if (type$1 !== "" && IS_WORKSPACE) {
266
269
  commander.program.option("-f, --filter <filter>", filterDescription);
267
270
  }
268
271
 
272
+ function Main() {
273
+ const { useState, useMemo, useEffect, useCallback } = React;
274
+ const [path, setPath] = useState(() => location.pathname.replace(/^\/ana\/?/, ""));
275
+ const [pkgName, entry] = useMemo(() => {
276
+ const pkgName2 = /^(@[^/]+\/[^/]+|[^/]+)\/?/.exec(path)?.[1];
277
+ return [
278
+ pkgName2,
279
+ pkgName2 != null ? path.replace(`${pkgName2}/`, "") : void 0
280
+ ];
281
+ }, [path]);
282
+ const push = useCallback((newPath) => {
283
+ setPath(newPath);
284
+ document.title = `${document.title.replace(/ - \/.*/, "")} - /${newPath}`;
285
+ history.pushState(null, "", `/ana/${newPath}`);
286
+ }, []);
287
+ const filterModules = useCallback((startWith) => {
288
+ const modules = analyzeModule.filter((m) => m.filename.startsWith(startWith));
289
+ dispatchEvent(new CustomEvent("send:filter", { detail: { analyzeModule: modules } }));
290
+ }, []);
291
+ useEffect(() => {
292
+ if (path !== "") {
293
+ document.title = `${document.title.replace(/ - \/.*/, "")} - /${path}`;
294
+ } else {
295
+ document.title = document.title.replace(/ - \/.*/, "");
296
+ }
297
+ filterModules(path);
298
+ }, [path, filterModules]);
299
+ useEffect(() => {
300
+ const offGraphClick = listen("graph:click", ({ detail }) => {
301
+ if (!detail) return;
302
+ let root = detail.node;
303
+ while (root.parent) {
304
+ root = root.parent;
305
+ }
306
+ if (root.filename === path) return;
307
+ push(root.filename);
308
+ });
309
+ return () => {
310
+ offGraphClick();
311
+ };
312
+ }, [push]);
313
+ function listen(type, listener) {
314
+ window.addEventListener(type, listener);
315
+ return () => {
316
+ window.removeEventListener(type, listener);
317
+ };
318
+ }
319
+ return /* @__PURE__ */ React.createElement(
320
+ "div",
321
+ {
322
+ style: {
323
+ padding: "12px 55px"
324
+ }
325
+ },
326
+ "/",
327
+ /* @__PURE__ */ React.createElement(
328
+ "select",
329
+ {
330
+ style: {
331
+ appearance: "none",
332
+ border: "none",
333
+ background: "none"
334
+ },
335
+ value: pkgName,
336
+ onChange: (e) => push(e.target.value)
337
+ },
338
+ /* @__PURE__ */ React.createElement("option", { value: "" }, "All"),
339
+ analyzeModule.map((m) => /^(@[^/]+\/[^/]+|[^/]+)\/?/.exec(m.filename)?.[1]).filter((v, i, a) => a.indexOf(v) === i).map((v) => /* @__PURE__ */ React.createElement("option", { key: v, value: v }, v))
340
+ ),
341
+ pkgName != null && /* @__PURE__ */ React.createElement(React.Fragment, null, "/", /* @__PURE__ */ React.createElement(
342
+ "select",
343
+ {
344
+ style: {
345
+ appearance: "none",
346
+ border: "none",
347
+ background: "none"
348
+ },
349
+ value: entry,
350
+ onChange: (e) => push(`${pkgName}/${e.target.value}`)
351
+ },
352
+ /* @__PURE__ */ React.createElement("option", { value: "" }, "All"),
353
+ analyzeModule.filter((m) => m.filename.startsWith(`${pkgName}/`)).map((m) => m.filename.replace(`${pkgName}/`, "")).filter((v, i, a) => a.indexOf(v) === i).map((v) => /* @__PURE__ */ React.createElement("option", { key: v, value: v }, v))
354
+ ))
355
+ );
356
+ }
357
+
358
+ function render() {
359
+ CUSTOM_SIDE_BAR = true;
360
+ window.addEventListener("client:ready", () => setTimeout(() => {
361
+ window.dispatchEvent(
362
+ new CustomEvent("send:ui", {
363
+ detail: { type: "Main", Component: __REPLACE_INJECT__ }
364
+ })
365
+ );
366
+ }, 0));
367
+ }
368
+ const CLIENT_CUSTOM_RENDER_SCRIPT = [
369
+ Main.toString(),
370
+ render.toString().replace("__REPLACE_INJECT__", Main.name),
371
+ `(${render.name})()`
372
+ ].join("\n");
373
+
374
+ function parseBoolean(v) {
375
+ if (v === void 0) return true;
376
+ return Boolean(v);
377
+ }
378
+
379
+ async function checkDependency(dependency) {
380
+ try {
381
+ require.resolve(dependency);
382
+ } catch {
383
+ console.error(`The package '${dependency}' is not installed, please install it first.`);
384
+ const { notWorkspace } = getWD();
385
+ const command = `pnpm install -${notWorkspace ? "" : "w"}D ${dependency}`;
386
+ if (await prompts.confirm({ message: "Do you want to install it now?" })) {
387
+ await execa.execaCommand(command);
388
+ } else {
389
+ console.warn(`You can run the command '${command}' to install it manually.`);
390
+ process__default.default.exit(1);
391
+ }
392
+ }
393
+ }
394
+
395
+ const registerAnalyzerCommandOptions = (command) => command.option("--ana", "Enable the bundle analyzer.", parseBoolean).option("--ana.dir <DIR>", "The directory of the bundle analyzer.", ".jk-analyses").option(
396
+ "--ana.mode <MODE>",
397
+ 'The mode of the bundle analyzer, support "static", "json" and "server".',
398
+ "server"
399
+ ).option("--ana.open", "Open the bundle analyzer in the browser.", parseBoolean).option(
400
+ "--ana.size <SIZE>",
401
+ 'The default size of the bundle analyzer, support "stat", "parsed" and "gzip".',
402
+ "parsed"
403
+ );
404
+ const useAnalyzer = async (options, server) => {
405
+ const modules = [];
406
+ let bundleAnalyzerModule;
407
+ const analyzer = options.ana ? {
408
+ dir: options["ana.dir"],
409
+ mode: options["ana.mode"],
410
+ open: options["ana.open"],
411
+ size: options["ana.size"]
412
+ } : void 0;
413
+ if (options.ana && ![
414
+ "stat",
415
+ "parsed",
416
+ "gzip"
417
+ ].includes(analyzer?.size ?? "")) {
418
+ throw new Error('The value of `ana.size` must be "stat", "parsed" or "gzip"');
419
+ }
420
+ if (analyzer) {
421
+ await checkDependency("vite-bundle-analyzer");
422
+ bundleAnalyzerModule = await import('vite-bundle-analyzer');
423
+ }
424
+ const refreshAnalyzer = async (cwd, applyModules) => {
425
+ if (!(analyzer && server && bundleAnalyzerModule)) return;
426
+ if (analyzer.mode === "json") {
427
+ const anaDir = path__default.default.resolve(cwd, analyzer.dir);
428
+ if (!fs.existsSync(anaDir)) {
429
+ fs.mkdirSync(anaDir, { recursive: true });
430
+ }
431
+ const gitIgnorePath = path__default.default.resolve(anaDir, ".gitignore");
432
+ if (!fs.existsSync(gitIgnorePath)) {
433
+ fs.writeFileSync(gitIgnorePath, "*\n!.gitignore\n");
434
+ }
435
+ const npmIgnorePath = path__default.default.resolve(anaDir, ".npmignore");
436
+ if (!fs.existsSync(npmIgnorePath)) {
437
+ fs.writeFileSync(npmIgnorePath, "*\n");
438
+ }
439
+ if (!fs.statSync(anaDir).isDirectory()) {
440
+ throw new Error(`The directory '${anaDir}' is not a directory.`);
441
+ }
442
+ }
443
+ const { renderView, injectHTMLTag } = bundleAnalyzerModule;
444
+ applyModules.forEach((m) => {
445
+ const index = modules.findIndex(({ filename }) => filename === m.filename);
446
+ if (index === -1) {
447
+ modules.push(m);
448
+ } else {
449
+ modules[index] = m;
450
+ }
451
+ });
452
+ let html = await renderView(modules, {
453
+ title: `Jiek Analyzer`,
454
+ mode: analyzer.size
455
+ });
456
+ html = injectHTMLTag({
457
+ html,
458
+ injectTo: "body",
459
+ descriptors: [
460
+ { kind: "script", text: CLIENT_CUSTOM_RENDER_SCRIPT }
461
+ ]
462
+ });
463
+ void server.renderTo("/ana", html);
464
+ };
465
+ return {
466
+ modules,
467
+ refreshAnalyzer,
468
+ ANALYZER_ENV: {
469
+ JIEK_ANALYZER: analyzer ? JSON.stringify(analyzer) : void 0
470
+ }
471
+ };
472
+ };
473
+
269
474
  const BUILDER_TYPES = ["esbuild", "swc"];
270
475
  const BUILDER_TYPE_PACKAGE_NAME_MAP = {
271
476
  esbuild: "rollup-plugin-esbuild",
@@ -277,7 +482,11 @@ const createServer = (port, host) => {
277
482
  app.listen(port, host);
278
483
  const streams = /* @__PURE__ */ new Map();
279
484
  app.use(async (ctx) => {
280
- const stream = streams.get(ctx.path);
485
+ let stream = streams.get(ctx.path);
486
+ if (stream == null) {
487
+ const maybeKey = streams.keys().find((p) => ctx.path.startsWith(p));
488
+ stream = maybeKey != null ? streams.get(maybeKey) : void 0;
489
+ }
281
490
  if (stream != null) {
282
491
  ctx.body = stream;
283
492
  }
@@ -390,8 +599,7 @@ function loadConfig(dirOrOptions) {
390
599
  default:
391
600
  throw new Error(`unsupported config file type: ${ext}`);
392
601
  }
393
- if (!module)
394
- throw new Error("config file is empty");
602
+ if (!module) throw new Error("config file is empty");
395
603
  return module.default ?? module;
396
604
  }
397
605
 
@@ -405,21 +613,6 @@ Build the package according to the 'exports' field from the package.json.
405
613
  If you want to through the options to the \`rollup\` command, you can pass the options after '--'.
406
614
  ${isDefault ? "This command is the default command." : ""}
407
615
  `.trim();
408
- async function checkDependency(dependency) {
409
- try {
410
- require$1.resolve(dependency);
411
- } catch {
412
- console.error(`The package '${dependency}' is not installed, please install it first.`);
413
- const { notWorkspace } = getWD();
414
- const command2 = `pnpm install -${notWorkspace ? "" : "w"}D ${dependency}`;
415
- if (await prompts.confirm({ message: "Do you want to install it now?" })) {
416
- await execa.execaCommand(command2);
417
- } else {
418
- console.warn(`You can run the command '${command2}' to install it manually.`);
419
- process__default.default.exit(1);
420
- }
421
- }
422
- }
423
616
  let DEFAULT_BUILDER_TYPE;
424
617
  Object.entries(BUILDER_TYPE_PACKAGE_NAME_MAP).forEach(([type, packageName]) => {
425
618
  try {
@@ -431,11 +624,6 @@ Object.entries(BUILDER_TYPE_PACKAGE_NAME_MAP).forEach(([type, packageName]) => {
431
624
  if (!DEFAULT_BUILDER_TYPE) {
432
625
  DEFAULT_BUILDER_TYPE = "esbuild";
433
626
  }
434
- function parseBoolean(v) {
435
- if (v === void 0)
436
- return true;
437
- return Boolean(v);
438
- }
439
627
  const buildFilterDescription = `
440
628
  ${filterDescription}
441
629
  If you pass the --filter option, it will merge into the filters of the command.
@@ -474,11 +662,7 @@ command = command.description(description).option("-t, --type <TYPE>", `The type
474
662
  );
475
663
  command = command.option("--tsconfig <TSCONFIG>", "The path of the tsconfig file which is used to generate js and dts files.", String).option("--dtsconfig <DTSCONFIG>", "The path of the tsconfig file which is used to generate dts files.", String);
476
664
  command = command.option("-w, --watch", "Watch the file changes.", parseBoolean).option("-p, --port <PORT>", "The port of the server.", Number.parseInt, 8888);
477
- command = command.option("--ana", "Enable the bundle analyzer.", parseBoolean).option("--ana.dir <DIR>", "The directory of the bundle analyzer.", ".jk-analyses").option("--ana.mode <MODE>", 'The mode of the bundle analyzer, support "static", "json" and "server".', "server").option("--ana.open", "Open the bundle analyzer in the browser.", parseBoolean).option(
478
- "--ana.size <SIZE>",
479
- 'The default size of the bundle analyzer, support "stat", "parsed" and "gzip".',
480
- "parsed"
481
- );
665
+ command = registerAnalyzerCommandOptions(command);
482
666
  command = command.option("-s, --silent", "Don't display logs.", parseBoolean).option("-v, --verbose", "Display debug logs.", parseBoolean);
483
667
  command.action(async (commandFiltersOrEntries, options) => {
484
668
  let {
@@ -526,43 +710,14 @@ command.action(async (commandFiltersOrEntries, options) => {
526
710
  },
527
711
  []
528
712
  );
529
- const modules = [];
530
- const cjsModules = [];
531
- const esmModules = [];
532
- let render;
533
- const analyzer = options.ana ? {
534
- dir: options["ana.dir"],
535
- mode: options["ana.mode"],
536
- open: options["ana.open"],
537
- size: options["ana.size"]
538
- } : void 0;
539
- if (options.ana && ![
540
- "stat",
541
- "parsed",
542
- "gzip"
543
- ].includes(analyzer?.size ?? "")) {
544
- throw new Error('The value of `ana.size` must be "stat", "parsed" or "gzip"');
545
- }
546
- const server = analyzer && createServer(options.port, "localhost");
547
- if (analyzer) {
548
- await checkDependency("vite-bundle-analyzer");
549
- const { renderView } = await import('vite-bundle-analyzer');
550
- render = renderView;
551
- }
552
- const anaPaths = /* @__PURE__ */ new Set();
553
- const refreshAnalyzer = async (subPath = "", renderModules = modules) => {
554
- if (!(analyzer && server && render))
555
- return;
556
- const p = `/ana${subPath}`;
557
- anaPaths.add(p);
558
- void server.renderTo(
559
- p,
560
- await render(renderModules, {
561
- title: `Jiek Analyzer - ${subPath}`,
562
- mode: analyzer.size
563
- })
564
- );
565
- };
713
+ const shouldCreateServer = [
714
+ options.ana === true && options["ana.mode"] === "server"
715
+ ].some(Boolean);
716
+ const server = shouldCreateServer ? createServer(options.port, "localhost") : void 0;
717
+ const {
718
+ ANALYZER_ENV,
719
+ refreshAnalyzer
720
+ } = await useAnalyzer(options, server);
566
721
  const { build } = loadConfig();
567
722
  silent = silent ?? build?.silent ?? false;
568
723
  if (withoutMin && onlyMin) {
@@ -579,7 +734,7 @@ command.action(async (commandFiltersOrEntries, options) => {
579
734
  entries = void 0;
580
735
  }
581
736
  const env = {
582
- JIEK_ANALYZER: analyzer && JSON.stringify(analyzer),
737
+ ...ANALYZER_ENV,
583
738
  JIEK_BUILDER: type,
584
739
  JIEK_OUT_DIR: outdir,
585
740
  JIEK_CLEAN: String(!noClean),
@@ -621,27 +776,10 @@ command.action(async (commandFiltersOrEntries, options) => {
621
776
  const rollupBinaryPath = require$1.resolve("rollup").replace(/dist\/rollup.js$/, "dist/bin/rollup");
622
777
  let i = 0;
623
778
  await Promise.all(
624
- Object.entries(value).map(async ([dir, manifest]) => {
779
+ Object.entries(value).map(async ([pkgCWD, manifest]) => {
625
780
  if (manifest.name == null) {
626
781
  throw new Error("package.json must have a name field");
627
782
  }
628
- if (analyzer) {
629
- const anaDir = path__default.default.resolve(dir, analyzer.dir);
630
- if (!fs.existsSync(anaDir)) {
631
- fs.mkdirSync(anaDir, { recursive: true });
632
- }
633
- const gitIgnorePath = path__default.default.resolve(anaDir, ".gitignore");
634
- if (!fs.existsSync(gitIgnorePath)) {
635
- fs.writeFileSync(gitIgnorePath, "*\n!.gitignore\n");
636
- }
637
- const npmIgnorePath = path__default.default.resolve(anaDir, ".npmignore");
638
- if (!fs.existsSync(npmIgnorePath)) {
639
- fs.writeFileSync(npmIgnorePath, "*\n");
640
- }
641
- if (!fs.statSync(anaDir).isDirectory()) {
642
- throw new Error(`The directory '${anaDir}' is not a directory.`);
643
- }
644
- }
645
783
  const escapeManifestName = manifest.name.replace(/^@/g, "").replace(/\//g, "+");
646
784
  const configFile = resolveByJiekTemp(
647
785
  `${escapeManifestName ?? `anonymous-${i++}`}.rollup.config.js`
@@ -657,7 +795,7 @@ command.action(async (commandFiltersOrEntries, options) => {
657
795
  command2.push(...passThroughOptions);
658
796
  const child = execa.execaCommand(command2.join(" "), {
659
797
  ipc: true,
660
- cwd: dir,
798
+ cwd: pkgCWD,
661
799
  env: {
662
800
  ...env,
663
801
  JIEK_NAME: manifest.name,
@@ -673,8 +811,7 @@ command.action(async (commandFiltersOrEntries, options) => {
673
811
  "init",
674
812
  "progress",
675
813
  "watchChange"
676
- ].includes(e.type))
677
- return;
814
+ ].includes(e.type)) return;
678
815
  switch (e.type) {
679
816
  case "init": {
680
817
  const { leafMap, targetsLength } = e.data;
@@ -695,8 +832,7 @@ command.action(async (commandFiltersOrEntries, options) => {
695
832
  });
696
833
  leafs.forEach(({ input, path: path2 }) => {
697
834
  const key = `${input}:${path2}`;
698
- if (bars[key])
699
- return;
835
+ if (bars[key]) return;
700
836
  bars[key] = multiBars.create(50, 0, {
701
837
  pkgName: manifest.name,
702
838
  input: input.padEnd(inputMaxLen + 5),
@@ -717,8 +853,7 @@ command.action(async (commandFiltersOrEntries, options) => {
717
853
  message
718
854
  } = e.data;
719
855
  const bar = bars[`${input}:${path2}`];
720
- if (!bar)
721
- return;
856
+ if (!bar) return;
722
857
  const time = times[`${input}:${path2}`];
723
858
  bar.update(
724
859
  {
@@ -741,8 +876,7 @@ command.action(async (commandFiltersOrEntries, options) => {
741
876
  } = e.data;
742
877
  const key = `${input}:${path2}`;
743
878
  const bar = bars[key];
744
- if (!bar)
745
- return;
879
+ if (!bar) return;
746
880
  let time = times[key] ?? 1;
747
881
  if (!locks[key]) {
748
882
  time += 1;
@@ -763,41 +897,18 @@ command.action(async (commandFiltersOrEntries, options) => {
763
897
  const {
764
898
  data: {
765
899
  type: type2,
766
- path: path2,
767
900
  modules: pkgModules
768
901
  }
769
902
  } = e;
770
- pkgModules.forEach((m) => {
771
- const newM = {
903
+ void refreshAnalyzer(
904
+ pkgCWD,
905
+ pkgModules.map((m) => ({
772
906
  ...m,
907
+ type: type2,
773
908
  filename: `${manifest.name}/${m.filename}`,
774
909
  label: `${manifest.name}/${m.label}`
775
- };
776
- const pushOrReplace = (arr) => {
777
- const index = arr.findIndex(({ filename }) => filename === newM.filename);
778
- if (index === -1) {
779
- arr.push(newM);
780
- } else {
781
- arr[index] = newM;
782
- }
783
- };
784
- pushOrReplace(modules);
785
- if (type2 === "esm") {
786
- pushOrReplace(esmModules);
787
- }
788
- if (type2 === "cjs") {
789
- pushOrReplace(cjsModules);
790
- }
791
- });
792
- void refreshAnalyzer();
793
- void refreshAnalyzer(
794
- `/${type2}`,
795
- {
796
- cjs: cjsModules,
797
- esm: esmModules
798
- }[type2]
910
+ }))
799
911
  );
800
- void refreshAnalyzer(`/${type2}/${manifest.name}/${path2.slice(2)}`, pkgModules);
801
912
  break;
802
913
  }
803
914
  case "debug": {
@@ -834,17 +945,7 @@ ${errorStr}`)));
834
945
  }
835
946
  } finally {
836
947
  multiBars.stop();
837
- let message = "The build is complete";
838
- if (analyzer) {
839
- message += ` and the analyzer is running at http://localhost:${options.port}/ana in ${analyzer.mode} mode.
840
- `;
841
- message += analyzer.open ? " The browser will open automatically.\n" : "";
842
- if (anaPaths.size > 0) {
843
- message += `The analyzer has ${anaPaths.size} pages:
844
- ${Array.from(anaPaths).map((p) => `http://localhost:${options.port}${p}`).join("\n")}`;
845
- }
846
- }
847
- !silent && console.log(message);
948
+ !silent && console.log("Build complete");
848
949
  }
849
950
  });
850
951
 
@@ -40,6 +40,17 @@ interface TemplateOptions {
40
40
  } & rollup_plugin_esbuild.Options) | ({
41
41
  type: 'swc';
42
42
  } & rollup_plugin_swc3.PluginOptions);
43
+ features?: {
44
+ /**
45
+ * When use esbuild type builder, it will inject `supported.import-attributes` option.
46
+ * When use swc type builder, it will inject `jsc.experimental.keepImportAttributes` option.
47
+ *
48
+ * And it will auto set the rollup output externalImportAttributes and importAttributesKey options.
49
+ *
50
+ * @default true
51
+ */
52
+ keepImportAttributes?: boolean | 'assert';
53
+ };
43
54
  output?: {
44
55
  /**
45
56
  * @default true
@@ -40,6 +40,17 @@ interface TemplateOptions {
40
40
  } & rollup_plugin_esbuild.Options) | ({
41
41
  type: 'swc';
42
42
  } & rollup_plugin_swc3.PluginOptions);
43
+ features?: {
44
+ /**
45
+ * When use esbuild type builder, it will inject `supported.import-attributes` option.
46
+ * When use swc type builder, it will inject `jsc.experimental.keepImportAttributes` option.
47
+ *
48
+ * And it will auto set the rollup output externalImportAttributes and importAttributesKey options.
49
+ *
50
+ * @default true
51
+ */
52
+ keepImportAttributes?: boolean | 'assert';
53
+ };
43
54
  output?: {
44
55
  /**
45
56
  * @default true