@flatjs/evolve 2.1.0-next.11 → 2.1.0-next.12

Sign up to get free protection for your applications and to get access to all the features.
Files changed (125) hide show
  1. package/dist/constants.js +36 -1
  2. package/dist/create-webpack/create-externals.js +6 -1
  3. package/dist/create-webpack/create-optimization.js +43 -1
  4. package/dist/create-webpack/create-output.js +35 -1
  5. package/dist/create-webpack/create-performance.js +7 -1
  6. package/dist/create-webpack/create-plugins.js +78 -1
  7. package/dist/create-webpack/create-resolve.js +37 -1
  8. package/dist/create-webpack/create-rule-sets.js +20 -1
  9. package/dist/create-webpack/load-webpack-config.js +57 -1
  10. package/dist/create-webpack/resolve-public-path.js +15 -1
  11. package/dist/create-webpack/rule-sets/constants.js +3 -1
  12. package/dist/create-webpack/rule-sets/rule-assets.js +52 -1
  13. package/dist/create-webpack/rule-sets/rule-css.js +111 -1
  14. package/dist/create-webpack/rule-sets/rule-less.js +44 -1
  15. package/dist/create-webpack/rule-sets/rule-scripts.js +34 -1
  16. package/dist/create-webpack/rule-sets/rule-svg-icon.js +25 -1
  17. package/dist/create-webpack/rule-sets/rule-utils.js +10 -1
  18. package/dist/create-webpack/types.js +1 -1
  19. package/dist/default-options.js +83 -1
  20. package/dist/define-config/define-config.js +4 -1
  21. package/dist/define-config/index.js +1 -1
  22. package/dist/dev-server/add-compiler-to-dev-server.js +58 -1
  23. package/dist/dev-server/create-app-page-route.js +13 -1
  24. package/dist/dev-server/create-dev-server-compiler-task.js +55 -1
  25. package/dist/dev-server/create-dev-server-entries.js +25 -1
  26. package/dist/dev-server/create-dev-server.js +24 -1
  27. package/dist/dev-server/index.js +6 -1
  28. package/dist/dev-server/middlewares/create-page-middleware.js +33 -1
  29. package/dist/dev-server/middlewares/create-public-assets-middleware.js +25 -1
  30. package/dist/dev-server/middlewares/get-all-sorted-modules.js +24 -1
  31. package/dist/dev-server/middlewares/get-bundle-asset.js +7 -1
  32. package/dist/dev-server/middlewares/get-dev-server-host-uri.js +5 -1
  33. package/dist/dev-server/middlewares/get-hmr-runtime-chunks.js +14 -1
  34. package/dist/dev-server/middlewares/get-normalized-entry-name.js +14 -1
  35. package/dist/dev-server/middlewares/get-page-main-html.js +49 -1
  36. package/dist/dev-server/middlewares/get-page-module-html.js +123 -1
  37. package/dist/dev-server/middlewares/get-project-virtual-path.js +3 -1
  38. package/dist/dev-server/middlewares/get-runtime-manifest.js +25 -1
  39. package/dist/dev-server/middlewares/index.js +2 -1
  40. package/dist/dev-server/middlewares/types.js +1 -1
  41. package/dist/errors/evolve-build-error.js +10 -1
  42. package/dist/helpers/allow-px2rem-for-module.js +6 -1
  43. package/dist/helpers/assert-group-entry-item.js +19 -1
  44. package/dist/helpers/assert-single-compiler.js +45 -1
  45. package/dist/helpers/chunk-entry-map.js +21 -1
  46. package/dist/helpers/delete-object-keys.js +20 -1
  47. package/dist/helpers/enable-bundle-hashname-for-module.js +6 -1
  48. package/dist/helpers/filter-actived-entries.js +42 -1
  49. package/dist/helpers/flat-entry-map.js +11 -1
  50. package/dist/helpers/get-bundle-file-name.js +23 -1
  51. package/dist/helpers/get-git-root.js +4 -1
  52. package/dist/helpers/get-html-plugin-config.js +47 -1
  53. package/dist/helpers/get-max-process-tasks.js +7 -1
  54. package/dist/helpers/get-pacakge-dir.js +13 -1
  55. package/dist/helpers/get-runtime-cdn-base.js +21 -1
  56. package/dist/helpers/index.js +27 -1
  57. package/dist/helpers/is-deep-equal.js +67 -1
  58. package/dist/helpers/json-serializer.js +52 -1
  59. package/dist/helpers/merge-babel-options.js +45 -1
  60. package/dist/helpers/normalize-check-entry-options.js +28 -1
  61. package/dist/helpers/normalize-entry-map.js +59 -1
  62. package/dist/helpers/normalize-group-name.js +16 -1
  63. package/dist/helpers/normalize-page-proxy.js +9 -1
  64. package/dist/helpers/normalize-resolve-alias.js +7 -1
  65. package/dist/helpers/normalize-template-inject-tokens.js +22 -1
  66. package/dist/helpers/open-page.js +15 -1
  67. package/dist/helpers/print-log.js +49 -1
  68. package/dist/helpers/refresh-evolve-mock-options.js +34 -1
  69. package/dist/helpers/resolve-entry-map-input-files.js +20 -1
  70. package/dist/helpers/script-injects.js +39 -1
  71. package/dist/helpers/should-enable-react-fast-refresh.js +14 -1
  72. package/dist/helpers/split-to-entry-group.js +139 -1
  73. package/dist/helpers/verify-group-entry-options.js +21 -1
  74. package/dist/index.js +5 -1
  75. package/dist/load-config/index.js +1 -1
  76. package/dist/load-config/load-evolve-config.js +41 -1
  77. package/dist/load-config/types.js +1 -1
  78. package/dist/main/create-thread-worker.js +51 -1
  79. package/dist/main/env-verify.js +21 -1
  80. package/dist/main/get-worker-path.js +5 -1
  81. package/dist/main/index.js +4 -1
  82. package/dist/main/prepare-build.js +39 -1
  83. package/dist/main/prepare-serve.js +69 -1
  84. package/dist/main/prepare-static.js +30 -1
  85. package/dist/main/start-build-dynamic.js +171 -1
  86. package/dist/main/start-build-worker.js +44 -1
  87. package/dist/main/start-build.js +69 -1
  88. package/dist/main/start-group-entry-build.js +32 -1
  89. package/dist/main/start-serve.js +34 -1
  90. package/dist/main/start-static.js +19 -1
  91. package/dist/minimizer/create-minimizers.js +25 -1
  92. package/dist/minimizer/default-options.js +14 -1
  93. package/dist/minimizer/image-minimizer.js +65 -1
  94. package/dist/minimizer/index.js +1 -1
  95. package/dist/minimizer/terser-minimizer.js +15 -3
  96. package/dist/minimizer/types.js +1 -1
  97. package/dist/plugins/circular-dependency/circular-dependency-plugin.js +119 -1
  98. package/dist/plugins/circular-dependency/index.js +15 -1
  99. package/dist/plugins/clean-webpack/clean-webpack-plugin.js +173 -1
  100. package/dist/plugins/clean-webpack/index.js +22 -1
  101. package/dist/plugins/define-variable/define-variable-plugin.js +28 -1
  102. package/dist/plugins/define-variable/index.js +1 -1
  103. package/dist/plugins/html-inject-scripts/plugin-html-inject-script.js +27 -1
  104. package/dist/plugins/module-federation/external-template-remotes.js +92 -1
  105. package/dist/plugins/module-federation/index.js +1 -1
  106. package/dist/plugins/module-federation/module-federation.js +100 -1
  107. package/dist/plugins/multi-html/index.js +16 -1
  108. package/dist/plugins/multi-html/multi-html-cdn-plugin.js +83 -1
  109. package/dist/plugins/multi-html/multi-html-plugin.js +65 -1
  110. package/dist/plugins/ts-checker/index.js +1 -1
  111. package/dist/plugins/ts-checker/ts-checker-plugin.js +24 -1
  112. package/dist/types/index.js +8 -1
  113. package/dist/types/types-ci.js +1 -1
  114. package/dist/types/types-dev-server.js +1 -1
  115. package/dist/types/types-entry-map.js +1 -1
  116. package/dist/types/types-federation.js +1 -1
  117. package/dist/types/types-loader-options.d.ts +30 -3
  118. package/dist/types/types-loader-options.js +1 -1
  119. package/dist/types/types-modular-import.js +1 -1
  120. package/dist/types/types-multi-html.js +1 -1
  121. package/dist/types/types-options.js +1 -1
  122. package/dist/types/types-plugin-options.js +1 -1
  123. package/dist/types/types-threads-options.js +1 -1
  124. package/dist/types/types-webpack.js +1 -1
  125. package/package.json +2 -2
@@ -1 +1,92 @@
1
- import webpackSources from"webpack-sources";const PLUGIN_NAME="ExternalTemplateRemotesPlugin",isExternalModule=e=>"ExternalModule"===e.constructor.name;function extractUrlAndGlobal(e){const t=e.indexOf("@");if(t<=0||t===e.length-1)throw new Error(`Invalid request "${e}"`);return[e.substring(t+1),e.substring(0,t)]}export class ExternalTemplateRemotesPlugin{apply(e){e.hooks.make.tap(PLUGIN_NAME,(e=>{const t=[];e.hooks.buildModule.tap(PLUGIN_NAME,(e=>{isExternalModule(e)&&"script"===e.externalType&&t.push(e)})),e.hooks.afterCodeGeneration.tap(PLUGIN_NAME,(()=>{t.forEach((t=>{const o=extractUrlAndGlobal(t.request)[0],n=toExpression(o),r=e.codeGenerationResults.get(t,void 0).sources,s=r.get("javascript");if(s){const e=new webpackSources.RawSource(s.source().toString().replace(`"${o}"`,n));r.set("javascript",e)}}))}))}))}}function toExpression(e){const t=[],o=[];let n=!1,r=!1;for(const s of e)if("["===s){if(n){r=!0;break}n=!0,o.length&&(t.push(`"${o.join("")}"`),o.length=0)}else if("]"===s){if(!n){r=!0;break}n=!1,o.length&&(t.push(`${o.join("")}`),o.length=0),o.length=0}else o.push(s);if(n||r)throw new Error(`Invalid template URL "${e}"`);return o.length&&t.push(`"${o.join("")}"`),t.join(" + ")}
1
+ import webpackSources from 'webpack-sources';
2
+ const PLUGIN_NAME = 'ExternalTemplateRemotesPlugin';
3
+ const isExternalModule = (module) => {
4
+ return module.constructor.name === 'ExternalModule';
5
+ };
6
+ /**
7
+ * @param {string} urlAndGlobal the script request
8
+ * @returns {string[]} script url and its global variable
9
+ */
10
+ function extractUrlAndGlobal(urlAndGlobal) {
11
+ const index = urlAndGlobal.indexOf('@');
12
+ if (index <= 0 || index === urlAndGlobal.length - 1) {
13
+ throw new Error(`Invalid request "${urlAndGlobal}"`);
14
+ }
15
+ return [urlAndGlobal.substring(index + 1), urlAndGlobal.substring(0, index)];
16
+ }
17
+ export class ExternalTemplateRemotesPlugin {
18
+ apply(compiler) {
19
+ compiler.hooks.make.tap(PLUGIN_NAME, (compilation) => {
20
+ const scriptExternalModules = [];
21
+ compilation.hooks.buildModule.tap(PLUGIN_NAME, (module) => {
22
+ if (isExternalModule(module) && module.externalType === 'script') {
23
+ scriptExternalModules.push(module);
24
+ }
25
+ });
26
+ compilation.hooks.afterCodeGeneration.tap(PLUGIN_NAME, () => {
27
+ scriptExternalModules.forEach((module) => {
28
+ const urlTemplate = extractUrlAndGlobal(module.request)[0];
29
+ const urlExpression = toExpression(urlTemplate);
30
+ const sourceMap = compilation.codeGenerationResults.get(module, undefined).sources;
31
+ const rawSource = sourceMap.get('javascript');
32
+ if (rawSource) {
33
+ const source = new webpackSources.RawSource(rawSource
34
+ .source()
35
+ .toString()
36
+ .replace(`"${urlTemplate}"`, urlExpression));
37
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
38
+ sourceMap.set('javascript', source);
39
+ }
40
+ });
41
+ });
42
+ });
43
+ }
44
+ }
45
+ /**
46
+ * app2@localhost/remoteEntry.js --> "\"app2@localhost/remoteEntry.js\""
47
+ * app2@[window.app2Url]/remoteEntry.js --> "\"app2@\" + window.app2Url + \"/remoteEntry.js\""
48
+ * @param templateUrl
49
+ * @returns
50
+ */
51
+ // eslint-disable-next-line sonarjs/cognitive-complexity
52
+ function toExpression(templateUrl) {
53
+ const result = [];
54
+ const current = [];
55
+ let isExpression = false;
56
+ let invalid = false;
57
+ for (const c of templateUrl) {
58
+ if (c === '[') {
59
+ if (isExpression) {
60
+ invalid = true;
61
+ break;
62
+ }
63
+ isExpression = true;
64
+ if (current.length) {
65
+ result.push(`"${current.join('')}"`);
66
+ current.length = 0;
67
+ }
68
+ }
69
+ else if (c === ']') {
70
+ if (!isExpression) {
71
+ invalid = true;
72
+ break;
73
+ }
74
+ isExpression = false;
75
+ if (current.length) {
76
+ result.push(`${current.join('')}`);
77
+ current.length = 0;
78
+ }
79
+ current.length = 0;
80
+ }
81
+ else {
82
+ current.push(c);
83
+ }
84
+ }
85
+ if (isExpression || invalid) {
86
+ throw new Error(`Invalid template URL "${templateUrl}"`);
87
+ }
88
+ if (current.length) {
89
+ result.push(`"${current.join('')}"`);
90
+ }
91
+ return result.join(' + ');
92
+ }
@@ -1 +1 @@
1
- export*from"./module-federation.js";
1
+ export * from './module-federation.js';
@@ -1 +1,100 @@
1
- import{join}from"node:path";import{ensureSlash}from"@flatjs/common";import webpack from"webpack";import{normalizeEvolveEntryName}from"../../helpers/normalize-entry-map.js";import{injectFederationScripts}from"../../helpers/script-injects.js";import{HtmlInjectScriptPlugin}from"../html-inject-scripts/plugin-html-inject-script.js";import{ExternalTemplateRemotesPlugin}from"./external-template-remotes.js";const normalizeWidgetName=(e="")=>e.replace(/[/-]/g,"_").toLowerCase(),remoteFileName=e=>join(e,"micro-remote-module.js");export const createModuleFederationPlugin=(e,t,o)=>{const r=o.projectVirtualPath,n=o.multiHtmlCdn,i=o.multiHtmlCdnEnvResolver,m=[];for(const o of t){const[t,a]=o,l=a.options?.moduleFederation;if(l){const{remotes:o,exposes:a,...s}=l,c=remoteFileName(t),p=normalizeWidgetName(t),u=(a?Array.isArray(a)?a:[a]:[]).map((e=>{const o={};for(const[r,n]of Object.entries(e))o[r]={...n,name:join(t,n.name.replace(/^\//,""))};return o})),d=(o||[]).map((({name:e,endpoint:t})=>{const o=normalizeEvolveEntryName(e,r),n=normalizeWidgetName(o),i=remoteFileName(o),m=t?ensureSlash(t(e,o),!1):"[window.evolveFetchMicroWidgets()]";return{[n]:`${n}@${m}/${i}`}}));m.push(new webpack.container.ModuleFederationPlugin({...s,name:p,filename:c,remotes:d,exposes:u}),new ExternalTemplateRemotesPlugin),e||m.unshift(new HtmlInjectScriptPlugin([injectFederationScripts(n,i)]))}}return m};
1
+ import { join } from 'node:path';
2
+ import { ensureSlash } from '@flatjs/common';
3
+ import webpack from 'webpack';
4
+ import { normalizeEvolveEntryName } from '../../helpers/normalize-entry-map.js';
5
+ import { injectFederationScripts } from '../../helpers/script-injects.js';
6
+ import { HtmlInjectScriptPlugin } from '../html-inject-scripts/plugin-html-inject-script.js';
7
+ import { ExternalTemplateRemotesPlugin } from './external-template-remotes.js';
8
+ /**
9
+ * `${projectVirtualPath}/mine` --> evolve_demo_mine
10
+ * @param entryPath `${projectVirtualPath}/mine`
11
+ */
12
+ const normalizeWidgetName = (entryPath = '') => {
13
+ return entryPath.replace(/[/-]/g, '_').toLowerCase();
14
+ };
15
+ const remoteFileName = (entryName) => {
16
+ return join(entryName, `micro-remote-module.js`);
17
+ };
18
+ export const createModuleFederationPlugin = (serveMode, entryMapItemList, evolveOptions) => {
19
+ const projectVirtualPath = evolveOptions.projectVirtualPath;
20
+ const multiCdnConfig = evolveOptions.multiHtmlCdn;
21
+ const multiHtmlCdnResolver = evolveOptions.multiHtmlCdnEnvResolver;
22
+ const plugins = [];
23
+ for (const entryMapItem of entryMapItemList) {
24
+ const [entryName, entryConfig] = entryMapItem;
25
+ const moduleFederation = entryConfig.options?.moduleFederation;
26
+ if (moduleFederation) {
27
+ const { remotes, exposes, ...restFederationOptions } = moduleFederation;
28
+ // e.g. `flatjs/evolve/mine` => `flatjs/evolve/home/micro-remote-module.js`
29
+ const entryRemoteFileName = remoteFileName(entryName);
30
+ // e.g. `flatjs/evolve/mine` => `flatjs_evolve_mine`
31
+ const containerName = normalizeWidgetName(entryName);
32
+ const patchExposes = exposes
33
+ ? Array.isArray(exposes)
34
+ ? exposes
35
+ : [exposes]
36
+ : [];
37
+ const myExposes = patchExposes.map((s) => {
38
+ const exposeItem = {};
39
+ for (const [key, config] of Object.entries(s)) {
40
+ exposeItem[key] = {
41
+ ...config,
42
+ name: join(entryName, config.name.replace(/^\//, '')),
43
+ };
44
+ }
45
+ return exposeItem;
46
+ });
47
+ const myRemotes = (remotes || []).map(({ name, endpoint }) => {
48
+ // e.g. `flatjs/evolve/home`
49
+ const normalizedEntryName = normalizeEvolveEntryName(name, projectVirtualPath);
50
+ // e.g. `flatjs_evolve_home`
51
+ const remoteWidgetName = normalizeWidgetName(normalizedEntryName);
52
+ // e.g. `flatjs/evolve/home/micro-remote-module.js`
53
+ const refRemoteEntryFileName = remoteFileName(normalizedEntryName);
54
+ // construct endpoint for remote widget name.
55
+ const endpointPath = endpoint
56
+ ? ensureSlash(endpoint(name, normalizedEntryName), false)
57
+ : `[window.evolveFetchMicroWidgets()]`;
58
+ return {
59
+ [remoteWidgetName]: `${remoteWidgetName}@${endpointPath}/${refRemoteEntryFileName}`,
60
+ };
61
+ });
62
+ plugins.push(
63
+ // https://webpack.js.org/plugins/module-federation-plugin/
64
+ new webpack.container.ModuleFederationPlugin({
65
+ /**
66
+ * Options for library.
67
+ * library: { type: 'var', name: containerName },
68
+ * other module federation configurations
69
+ */
70
+ ...restFederationOptions,
71
+ /**
72
+ * The name of the container
73
+ * `${projectName}-${moduleName}` e.g. `flatjs_evolve_home`
74
+ */
75
+ name: containerName,
76
+ /**
77
+ * The filename of the container as relative path inside the `output.path` directory.
78
+ * `${entryName}/micro-remote-module.js`, e.g. `flatjs/evolve/home/micro-remote-module.js`
79
+ */
80
+ filename: entryRemoteFileName,
81
+ /**
82
+ * Container locations and request scopes from which modules should be resolved and loaded at runtime.
83
+ * When provided, property name is used as request scope, otherwise request scope is automatically inferred from container location.
84
+ */
85
+ remotes: myRemotes,
86
+ /**
87
+ * Modules that should be exposed by this container.
88
+ * When provided, property name is used as public name, otherwise public name is automatically inferred from request.
89
+ */
90
+ exposes: myExposes,
91
+ }), new ExternalTemplateRemotesPlugin());
92
+ if (!serveMode) {
93
+ plugins.unshift(new HtmlInjectScriptPlugin([
94
+ injectFederationScripts(multiCdnConfig, multiHtmlCdnResolver),
95
+ ]));
96
+ }
97
+ }
98
+ }
99
+ return plugins;
100
+ };
@@ -1 +1,16 @@
1
- import{FlatEvolveMultiCdnPlugin}from"./multi-html-cdn-plugin.js";import{createMultiHtmlWebpackPlugin}from"./multi-html-plugin.js";export const createHtmlPlugins=(t,l,u)=>{const i=[],n=l[0];if(t||n[1]?.options?.output?.library)return i;const e=Object.keys(u.multiHtmlCdn);return i.push(...createMultiHtmlWebpackPlugin(t,u,l,e)),i.push(new FlatEvolveMultiCdnPlugin(u)),i};
1
+ import { FlatEvolveMultiCdnPlugin } from './multi-html-cdn-plugin.js';
2
+ import { createMultiHtmlWebpackPlugin } from './multi-html-plugin.js';
3
+ export const createHtmlPlugins = (serveMode, entryMapItemList, evolveOptions) => {
4
+ const plugins = [];
5
+ // Only for `production`, or `library` compiler mode do not need to attach `html-webpack-plugin`
6
+ const firstEntryMapItem = entryMapItemList[0];
7
+ if (serveMode || firstEntryMapItem[1]?.options?.output?.library) {
8
+ return plugins;
9
+ }
10
+ // Attach `html-webpack-plugin` first
11
+ const allEnv = Object.keys(evolveOptions.multiHtmlCdn);
12
+ plugins.push(...createMultiHtmlWebpackPlugin(serveMode, evolveOptions, entryMapItemList, allEnv));
13
+ // Attach `@flatjs/evolve-plugin-multi-html-cdn`
14
+ plugins.push(new FlatEvolveMultiCdnPlugin(evolveOptions));
15
+ return plugins;
16
+ };
@@ -1 +1,83 @@
1
- import{basename}from"node:path";import HtmlWebpackPlugin from"html-webpack-plugin";import webpack from"webpack";import{getRuntimeCDNBase}from"../../helpers/get-runtime-cdn-base.js";import{findEnvCdn,httpUrlJoin}from"../../helpers/script-injects.js";export class FlatEvolveMultiCdnPlugin{constructor(e){if(this.pluginName="FlatEvolveMultiCdnPlugin",this.requireFn=webpack.RuntimeGlobals.publicPath,this.config=e.multiHtmlCdn,this.cdnResolver=e.multiHtmlCdnEnvResolver||function cdnResolver(){},!this.config?.prod)throw new Error("We must setup `prod` for each CDN config node!")}apply(e){e.hooks.thisCompilation.tap(this.pluginName,(e=>{e.mainTemplate.hooks.requireExtensions.tap(this.pluginName,((t,n)=>{const i=[];i.push("// Dynamic assets path override(`@flatjs/evolve`) plugin-multi-html-cdn`)");const s=e.chunkGraph?.getTreeRuntimeRequirements(n);return s&&s.has(webpack.RuntimeGlobals.requireScope)&&i.push(webpack.Template.indent(getRuntimeCDNBase(this.config,this.cdnResolver,this.requireFn))),webpack.Template.asString(i)}))})),e.hooks.compilation.tap(this.pluginName,(e=>{HtmlWebpackPlugin.getHooks(e).beforeAssetTagGeneration.tap(this.pluginName,(e=>{const{assets:t,plugin:n,outputName:i}=e,s=n?.options?.chunks||[],r=Array.isArray(s)?s.find((e=>i.includes(e))):s,{userOptions:o}=e.plugin;if(!r)throw new Error("We must have current chunk!");const a=t.js.filter((e=>e.includes(r))),l=t.css.filter((e=>e.includes(r))),p=o.multiCdn,u=t.publicPath,c=a.map((e=>{if(p.disabled)return basename(e);const t=findEnvCdn(this.config,p.env);return httpUrlJoin(t,e.replace(u,""))})),m=l.map((e=>{if(p.disabled)return basename(e);const t=findEnvCdn(this.config,p.env);return httpUrlJoin(t,e.replace(u,""))}));return e.assets.js=c,e.assets.css=m,e}))}))}}
1
+ import { basename } from 'node:path';
2
+ import HtmlWebpackPlugin from 'html-webpack-plugin';
3
+ import webpack from 'webpack';
4
+ import { getRuntimeCDNBase } from '../../helpers/get-runtime-cdn-base.js';
5
+ import { findEnvCdn, httpUrlJoin } from '../../helpers/script-injects.js';
6
+ export class FlatEvolveMultiCdnPlugin {
7
+ constructor(evolveOptions) {
8
+ this.pluginName = 'FlatEvolveMultiCdnPlugin';
9
+ // https://github.com/webpack/webpack/blob/3d653290fafe385277b48e5a36807124618b9561/lib/MainTemplate.js#L12
10
+ // the bundle public path RuntimeGlobals.publicPath: '__webpack_require__.p';
11
+ this.requireFn = webpack.RuntimeGlobals.publicPath;
12
+ this.config = evolveOptions.multiHtmlCdn;
13
+ this.cdnResolver =
14
+ evolveOptions.multiHtmlCdnEnvResolver ||
15
+ function cdnResolver() {
16
+ return undefined;
17
+ };
18
+ // Make sure we have `prod` configuration for each cdn node at least.
19
+ if (!this.config?.prod) {
20
+ throw new Error('We must setup `prod` for each CDN config node!');
21
+ }
22
+ }
23
+ /**
24
+ * Apply the plugin to check if there are non initial chunks which need to be imported using `require-ensure` or `import`
25
+ * https://github.com/webpack/webpack/blob/3d653290fafe385277b48e5a36807124618b9561/lib/MainTemplate.js#L158
26
+ * https://www.npmjs.com/package/vscode-webpack-debugger
27
+ * https://www.cnblogs.com/Scar007/p/9166068.html
28
+ * https://www.cnblogs.com/pluslius/p/10271537.html
29
+ */
30
+ apply(compiler) {
31
+ // Handle chunk assets while `Compilation:before-chunk-assets`
32
+ // https://github.com/webpack/webpack/blob/3d653290fafe385277b48e5a36807124618b9561/lib/MainTemplate.js#L58
33
+ compiler.hooks.thisCompilation.tap(this.pluginName, (compilation) => {
34
+ compilation.mainTemplate.hooks.requireExtensions.tap(this.pluginName, (_source, chunk) => {
35
+ const buf = [];
36
+ buf.push('// Dynamic assets path override(`@flatjs/evolve`) plugin-multi-html-cdn`)');
37
+ const runtimeRequirements = compilation.chunkGraph?.getTreeRuntimeRequirements(chunk);
38
+ if (runtimeRequirements &&
39
+ runtimeRequirements.has(webpack.RuntimeGlobals.requireScope)) {
40
+ buf.push(webpack.Template.indent(getRuntimeCDNBase(this.config, this.cdnResolver, this.requireFn)));
41
+ }
42
+ return webpack.Template.asString(buf);
43
+ });
44
+ });
45
+ // Using html webpack plugin hooks to replace `scripts` `styles` before inject to html temlate file.
46
+ compiler.hooks.compilation.tap(this.pluginName, (compilation) => {
47
+ HtmlWebpackPlugin.getHooks(compilation).beforeAssetTagGeneration.tap(this.pluginName, (data) => {
48
+ const { assets, plugin, outputName } = data;
49
+ const chunks = plugin?.options?.chunks || [];
50
+ const currentChunk = Array.isArray(chunks)
51
+ ? chunks.find((chunk) => outputName.includes(chunk))
52
+ : chunks;
53
+ const { userOptions } = data.plugin;
54
+ if (!currentChunk) {
55
+ throw new Error('We must have current chunk!');
56
+ }
57
+ const assertJsList = assets.js.filter((jsPath) => jsPath.includes(currentChunk));
58
+ const assertCssList = assets.css.filter((jsPath) => jsPath.includes(currentChunk));
59
+ const multiCdn = userOptions.multiCdn;
60
+ const publicPath = assets.publicPath;
61
+ const scripts = assertJsList.map((scriptItem) => {
62
+ // Normally for `index-dev.html` we need to use relative path.
63
+ if (multiCdn.disabled) {
64
+ return basename(scriptItem);
65
+ }
66
+ const randomCdn = findEnvCdn(this.config, multiCdn.env);
67
+ return httpUrlJoin(randomCdn, scriptItem.replace(publicPath, ''));
68
+ });
69
+ const styles = assertCssList.map((styleItem) => {
70
+ // Normally for `index-dev.html` we need to use relative path.
71
+ if (multiCdn.disabled) {
72
+ return basename(styleItem);
73
+ }
74
+ const randomCdn = findEnvCdn(this.config, multiCdn.env);
75
+ return httpUrlJoin(randomCdn, styleItem.replace(publicPath, ''));
76
+ });
77
+ data.assets.js = scripts;
78
+ data.assets.css = styles;
79
+ return data;
80
+ });
81
+ });
82
+ }
83
+ }
@@ -1 +1,65 @@
1
- import HtmlWebpackPlugin from"html-webpack-plugin";import{allowPx2remForModule}from"../../helpers/allow-px2rem-for-module.js";import{getHtmlPluginConfig}from"../../helpers/get-html-plugin-config.js";import{normalizeTemplateInjectTokens}from"../../helpers/normalize-template-inject-tokens.js";import{findEnvCdn}from"../../helpers/script-injects.js";const minifyOpts={minifyJS:!0,removeComments:!0,collapseWhitespace:!0,collapseBooleanAttributes:!1};export const createMultiHtmlWebpackPlugin=(e,t,l,n)=>{const i=l[0],[,o]=i,m=[],{options:p}=o,r=e?"development":"production",a=l.map((e=>e[0]));for(const e of n){const l={mode:r,envCdn:findEnvCdn(t.multiHtmlCdn,e)},n=normalizeTemplateInjectTokens(l,p);m.push(new HtmlWebpackPlugin({inject:"body",title:getHtmlPluginConfig("title",l,p?.title),chunks:a,minify:!1!==p?.htmlMinify&&!["me","dev"].includes(e)&&minifyOpts,filename:t=>`${t}/index${"prod"===e?"":`-${e}`}.html`,template:getHtmlPluginConfig("templatePath",l,p?.templatePath).replace("{0}",e),templateParameters:{title:getHtmlPluginConfig("title",l,p?.title),favicon:getHtmlPluginConfig("favicon",l,p?.favicon),viewport:allowPx2remForModule(i,t)?getHtmlPluginConfig("viewport",l,p?.viewport):"",...n},multiCdn:{env:e,disabled:(p?.excludeCdnEnvs||["me","dev","ntv"]).includes(e)}}))}return m};
1
+ import HtmlWebpackPlugin from 'html-webpack-plugin';
2
+ import { allowPx2remForModule } from '../../helpers/allow-px2rem-for-module.js';
3
+ import { getHtmlPluginConfig, } from '../../helpers/get-html-plugin-config.js';
4
+ import { normalizeTemplateInjectTokens } from '../../helpers/normalize-template-inject-tokens.js';
5
+ import { findEnvCdn } from '../../helpers/script-injects.js';
6
+ const minifyOpts = {
7
+ minifyJS: true,
8
+ removeComments: true,
9
+ collapseWhitespace: true,
10
+ collapseBooleanAttributes: false,
11
+ };
12
+ /**
13
+ * Create `html-webpack-plugin` for this build, refer to best practices
14
+ * We'd better pass only one entry for each `build` cycle
15
+ * @param buildEntryItem the entries for this `build`
16
+ * @param allEnv
17
+ */
18
+ export const createMultiHtmlWebpackPlugin = (serveMode, evolveOptions, entryMapItemList, allEnv) => {
19
+ const firstEntryMap = entryMapItemList[0];
20
+ const [, entryConfig] = firstEntryMap;
21
+ const htmlPlugins = [];
22
+ const { options } = entryConfig;
23
+ const mode = serveMode ? 'development' : 'production';
24
+ const chunks = entryMapItemList.map((entryMap) => entryMap[0]);
25
+ for (const env of allEnv) {
26
+ const envCdn = findEnvCdn(evolveOptions.multiHtmlCdn, env);
27
+ const configData = {
28
+ mode,
29
+ envCdn,
30
+ };
31
+ const templateInjectTokens = normalizeTemplateInjectTokens(configData, options);
32
+ htmlPlugins.push(new HtmlWebpackPlugin({
33
+ inject: 'body',
34
+ title: getHtmlPluginConfig('title', configData, options?.title),
35
+ chunks: chunks,
36
+ // `minify` is true, `dev` always don't minify.
37
+ minify: options?.htmlMinify === false || ['me', 'dev'].includes(env)
38
+ ? false
39
+ : minifyOpts,
40
+ // output file path
41
+ filename: (entryName) => `${entryName}/index${env === 'prod' ? '' : `-${env}`}.html`,
42
+ // html template
43
+ template: getHtmlPluginConfig('templatePath', configData, options?.templatePath).replace(`{0}`, env),
44
+ // template parameters
45
+ templateParameters: {
46
+ // The page title
47
+ title: getHtmlPluginConfig('title', configData, options?.title),
48
+ // The page favicon
49
+ favicon: getHtmlPluginConfig('favicon', configData, options?.favicon),
50
+ // `allowPx2rem` default is true
51
+ viewport: allowPx2remForModule(firstEntryMap, evolveOptions)
52
+ ? getHtmlPluginConfig('viewport', configData, options?.viewport)
53
+ : '',
54
+ ...templateInjectTokens,
55
+ },
56
+ // Some options for plugin used the `hook` of `html-webpack-plugin`
57
+ multiCdn: {
58
+ env,
59
+ // use relative path for `me`, `dev`, `ntv`
60
+ disabled: (options?.excludeCdnEnvs || ['me', 'dev', 'ntv']).includes(env),
61
+ },
62
+ }));
63
+ }
64
+ return htmlPlugins;
65
+ };
@@ -1 +1 @@
1
- export*from"./ts-checker-plugin.js";
1
+ export * from './ts-checker-plugin.js';
@@ -1 +1,24 @@
1
- import ForkTsCheckerWebpackPlugin from"fork-ts-checker-webpack-plugin";export const createTsCheckerPlugins=(e,r,t)=>{const c=[];let o=!1;for(const[,e]of r){if((e.entry||[]).find((e=>/.vue$/.test(e)))){o=!0;break}}return t.loaderOptions.runTsChecker&&!o&&c.push(new ForkTsCheckerWebpackPlugin({async:e,issue:{},typescript:{context:t.projectCwd,memoryLimit:8192}})),c};
1
+ import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin';
2
+ export const createTsCheckerPlugins = (serveMode, entryMapItemList, evolveOptions) => {
3
+ const plugins = [];
4
+ let isVueEntryItem = false;
5
+ for (const [, entryMapItem] of entryMapItemList) {
6
+ const itemEntries = entryMapItem.entry || [];
7
+ if (itemEntries.find((s) => /.vue$/.test(s))) {
8
+ isVueEntryItem = true;
9
+ break;
10
+ }
11
+ }
12
+ // Runs typescript type checker and linter on separate process.
13
+ if (evolveOptions.loaderOptions.runTsChecker && !isVueEntryItem) {
14
+ plugins.push(new ForkTsCheckerWebpackPlugin({
15
+ async: serveMode,
16
+ issue: {},
17
+ typescript: {
18
+ context: evolveOptions.projectCwd,
19
+ memoryLimit: 2048 * 4,
20
+ },
21
+ }));
22
+ }
23
+ return plugins;
24
+ };
@@ -1 +1,8 @@
1
- export*from"./types-dev-server.js";export*from"./types-entry-map.js";export*from"./types-federation.js";export*from"./types-modular-import.js";export*from"./types-multi-html.js";export*from"./types-options.js";export*from"./types-loader-options.js";export*from"./types-webpack.js";
1
+ export * from './types-dev-server.js';
2
+ export * from './types-entry-map.js';
3
+ export * from './types-federation.js';
4
+ export * from './types-modular-import.js';
5
+ export * from './types-multi-html.js';
6
+ export * from './types-options.js';
7
+ export * from './types-loader-options.js';
8
+ export * from './types-webpack.js';
@@ -1 +1 @@
1
- export{};
1
+ export {};
@@ -1 +1 @@
1
- export{};
1
+ export {};
@@ -1 +1 @@
1
- export{};
1
+ export {};
@@ -1 +1 @@
1
- export{};
1
+ export {};
@@ -1,6 +1,7 @@
1
1
  import { type TransformOptions } from '@babel/core';
2
2
  import { type PostcssPluginPixelOptions } from '@flatjs/forge-postcss-plugin-pixel';
3
3
  import { type AcceptedPlugin } from 'postcss';
4
+ import { type LoaderContext } from 'webpack';
4
5
  import { type ModularImportOption } from './types-modular-import.js';
5
6
  export type BabelInputOptions = Pick<TransformOptions, 'presets' | 'plugins'>;
6
7
  /**
@@ -14,6 +15,34 @@ export type BuiltinBabelOptions = BabelInputOptions & {
14
15
  */
15
16
  usePreset?: 'react' | 'vue';
16
17
  };
18
+ /**
19
+ * The configurations for `css-loader` modules
20
+ * https://github.com/webpack-contrib/css-loader/blob/master/README.md#modules
21
+ */
22
+ export type CssLoaderModules = boolean | 'local' | 'global' | 'pure' | 'icss' | Partial<{
23
+ auto: boolean | RegExp | ((resourcePath: string) => boolean);
24
+ mode: 'local' | 'global' | 'pure' | 'icss' | ((resourcePath: any) => 'local' | 'global' | 'pure' | 'icss');
25
+ localIdentName: string;
26
+ localIdentContext: string;
27
+ localIdentHashSalt: string;
28
+ localIdentHashFunction: string;
29
+ localIdentHashDigest: string;
30
+ localIdentRegExp: string | RegExp;
31
+ getLocalIdent: (context: LoaderContext<any>, localIdentName: string, localName: string) => string;
32
+ namedExport: boolean;
33
+ exportGlobals: boolean;
34
+ exportLocalsConvention: 'as-is' | 'camel-case' | 'camel-case-only' | 'dashes' | 'dashes-only' | ((name: string) => string);
35
+ exportOnlyLocals: boolean;
36
+ getJSON: ({ resourcePath, imports, exports, replacements, }: {
37
+ resourcePath: string;
38
+ imports: object[];
39
+ exports: object[];
40
+ replacements: object[];
41
+ }) => Promise<void> | void;
42
+ }>;
43
+ export type CssLoaderOptions = {
44
+ modules?: CssLoaderModules;
45
+ } & Record<string, unknown>;
17
46
  /**
18
47
  * The configurations for `builtin` rule set options
19
48
  */
@@ -28,9 +57,7 @@ export interface RuleSetLoaderOptions {
28
57
  * The configurations of `css-loader`
29
58
  * https://github.com/webpack-contrib/css-loader/blob/master/README.md#modules
30
59
  */
31
- cssLoaderOptions?: {
32
- modules?: Record<string, unknown>;
33
- } & Record<string, unknown>;
60
+ cssLoaderOptions?: CssLoaderOptions;
34
61
  /**
35
62
  * The config for `Less`
36
63
  */
@@ -1 +1 @@
1
- export{};
1
+ export {};
@@ -1 +1 @@
1
- export{};
1
+ export {};
@@ -1 +1 @@
1
- export{};
1
+ export {};
@@ -1 +1 @@
1
- export{};
1
+ export {};
@@ -1 +1 @@
1
- export{};
1
+ export {};
@@ -1 +1 @@
1
- export{};
1
+ export {};
@@ -1 +1 @@
1
- export{};
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flatjs/evolve",
3
- "version": "2.1.0-next.11",
3
+ "version": "2.1.0-next.12",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "exports": {
@@ -19,7 +19,7 @@
19
19
  ],
20
20
  "scripts": {
21
21
  "serve": "yarn node --import=@armit/path-alias/register ./tests/dev-server/dev-server.ts",
22
- "build": "rimraf dist && tsc -p ./tsconfig.build.json && npm run minify",
22
+ "build": "rimraf dist && tsc -p ./tsconfig.build.json",
23
23
  "?build-release": "When https://github.com/atlassian/changesets/issues/432 has a solution we can remove this trick",
24
24
  "build-release": "yarn build && rimraf ./_release && yarn pack && mkdir ./_release && tar zxvf ./package.tgz --directory ./_release && rm ./package.tgz",
25
25
  "minify": "node ../../scripts/minify.mjs --dest=dist",