@flatjs/evolve 1.8.1-next.66 → 1.8.1-next.68

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/constants.js +17 -1
  3. package/dist/create-webpack/create-externals.js +6 -1
  4. package/dist/create-webpack/create-optimization.js +29 -1
  5. package/dist/create-webpack/create-output.js +35 -1
  6. package/dist/create-webpack/create-performance.js +7 -1
  7. package/dist/create-webpack/create-plugins.js +78 -1
  8. package/dist/create-webpack/create-resolve.js +31 -1
  9. package/dist/create-webpack/create-rule-sets.js +16 -1
  10. package/dist/create-webpack/load-webpack-config.js +55 -1
  11. package/dist/create-webpack/rule-sets/constants.js +3 -1
  12. package/dist/create-webpack/rule-sets/rule-assets.js +44 -1
  13. package/dist/create-webpack/rule-sets/rule-css.js +84 -1
  14. package/dist/create-webpack/rule-sets/rule-less.js +45 -1
  15. package/dist/create-webpack/rule-sets/rule-scripts.js +27 -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 +79 -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 +47 -1
  23. package/dist/dev-server/create-app-page-route.js +11 -1
  24. package/dist/dev-server/create-dev-server-compiler-tasks.js +51 -1
  25. package/dist/dev-server/create-dev-server-entries.js +27 -1
  26. package/dist/dev-server/create-dev-server.js +23 -1
  27. package/dist/dev-server/index.js +6 -1
  28. package/dist/dev-server/middlewares/create-page-middleware.js +164 -1
  29. package/dist/dev-server/middlewares/create-public-assets-middleware.js +25 -1
  30. package/dist/dev-server/middlewares/index.js +2 -1
  31. package/dist/errors/evolve-build-error.js +10 -1
  32. package/dist/helpers/allow-px2rem-for-module.js +6 -1
  33. package/dist/helpers/assert-only-single-entry-item.js +23 -1
  34. package/dist/helpers/chunk-entry-map.js +21 -1
  35. package/dist/helpers/enable-bundle-hashname-for-module.js +6 -1
  36. package/dist/helpers/filter-actived-entries.d.ts +1 -1
  37. package/dist/helpers/filter-actived-entries.js +41 -1
  38. package/dist/helpers/get-bundle-file-name.js +23 -1
  39. package/dist/helpers/get-git-root.js +4 -1
  40. package/dist/helpers/get-html-plugin-config.d.ts +9 -1
  41. package/dist/helpers/get-html-plugin-config.js +47 -1
  42. package/dist/helpers/get-max-process-tasks.d.ts +1 -0
  43. package/dist/helpers/get-max-process-tasks.js +7 -0
  44. package/dist/helpers/get-pacakge-dir.js +13 -1
  45. package/dist/helpers/index.js +15 -1
  46. package/dist/helpers/merge-babel-options.js +45 -1
  47. package/dist/helpers/normalize-entry-map.js +38 -1
  48. package/dist/helpers/open-page.js +15 -1
  49. package/dist/helpers/print-log.js +49 -1
  50. package/dist/helpers/refresh-evolve-mock-options.js +23 -1
  51. package/dist/helpers/resolve-entry-map-input-files.js +20 -1
  52. package/dist/helpers/script-injects.js +39 -1
  53. package/dist/helpers/should-enable-react-fast-refresh.js +8 -1
  54. package/dist/helpers/split-to-multi-compiler.js +22 -1
  55. package/dist/index.js +5 -1
  56. package/dist/load-config/index.js +1 -1
  57. package/dist/load-config/load-evolve-config.js +35 -1
  58. package/dist/main/env-verify.js +21 -1
  59. package/dist/main/index.js +4 -1
  60. package/dist/main/prepare-build.d.ts +4 -8
  61. package/dist/main/prepare-build.js +38 -1
  62. package/dist/main/prepare-serve.js +36 -1
  63. package/dist/main/prepare-static.js +28 -1
  64. package/dist/main/start-build-dynamic.d.ts +2 -1
  65. package/dist/main/start-build-dynamic.js +144 -1
  66. package/dist/main/start-build-worker.d.ts +14 -0
  67. package/dist/main/start-build-worker.js +41 -0
  68. package/dist/main/start-build.d.ts +1 -8
  69. package/dist/main/start-build.js +49 -1
  70. package/dist/main/start-one-entry-build.d.ts +13 -0
  71. package/dist/main/start-one-entry-build.js +35 -0
  72. package/dist/main/start-serve.js +32 -1
  73. package/dist/main/start-static.js +16 -1
  74. package/dist/minimizer/create-minimizers.js +25 -1
  75. package/dist/minimizer/default-options.js +14 -1
  76. package/dist/minimizer/image-minimizer.js +56 -1
  77. package/dist/minimizer/index.js +1 -1
  78. package/dist/minimizer/terser-minimizer.js +15 -3
  79. package/dist/minimizer/types.js +1 -1
  80. package/dist/plugins/clean-webpack/clean-webpack-plugin.js +173 -1
  81. package/dist/plugins/clean-webpack/index.js +22 -1
  82. package/dist/plugins/define-variable/define-variable-plugin.js +21 -1
  83. package/dist/plugins/define-variable/index.js +1 -1
  84. package/dist/plugins/html-inject-scripts/plugin-html-inject-script.js +27 -1
  85. package/dist/plugins/module-federation/external-template-remotes.js +92 -1
  86. package/dist/plugins/module-federation/index.js +1 -1
  87. package/dist/plugins/module-federation/module-federation.js +98 -1
  88. package/dist/plugins/multi-html/index.js +15 -1
  89. package/dist/plugins/multi-html/multi-html-cdn-plugin.js +84 -1
  90. package/dist/plugins/multi-html/multi-html-plugin.js +70 -1
  91. package/dist/types/index.js +8 -1
  92. package/dist/types/types-ci.js +1 -1
  93. package/dist/types/types-dev-server.js +1 -1
  94. package/dist/types/types-entry-map.js +1 -1
  95. package/dist/types/types-federation.js +1 -1
  96. package/dist/types/types-loader-options.js +1 -1
  97. package/dist/types/types-modular-import.js +1 -1
  98. package/dist/types/types-multi-html.d.ts +6 -5
  99. package/dist/types/types-multi-html.js +1 -1
  100. package/dist/types/types-options.js +1 -1
  101. package/dist/types/types-plugin-options.js +1 -1
  102. package/dist/types/types-webpack.d.ts +1 -1
  103. package/dist/types/types-webpack.js +1 -1
  104. package/package.json +14 -12
  105. package/templates/html-plugin/index-dev.html +31 -38
  106. package/templates/html-plugin/index-inte.html +31 -38
  107. package/templates/html-plugin/index-inte2.html +31 -38
  108. package/templates/html-plugin/index-inte3.html +31 -38
  109. package/templates/html-plugin/index-inte4.html +31 -38
  110. package/templates/html-plugin/index-me.html +31 -38
  111. package/templates/html-plugin/index-prod.html +31 -38
  112. package/templates/html-plugin/index-rc.html +31 -38
  113. package/templates/html-plugin/index-uat.html +31 -38
  114. package/templates/module.html +40 -55
@@ -1 +1,79 @@
1
- export const defaultEvolveOptions={projectCwd:process.cwd(),projectVirtualPath:"flatjs/evolve",rejectWarnings:!1,devServer:{autoOpen:!0,mockOptions:{mockBaseDir:"mocks"},clientOverlay:{errors:!0,warnings:!1},middlewares:[],watchOptions:{poll:1e3,ignored:/node_modules/,aggregateTimeout:500},defaultServeGlobalData:()=>Promise.resolve({})},webpack:{target:["web","es5"],plugins:[],ruleSets:[],publicPath:"auto",externals:{vue:"Vue",react:"React","react-dom":"ReactDOM"},outputDir:"public",enableBundleHashName:!0},pluginOptions:{},loaderOptions:{assetDataUrlMaxSize:4096,babelOptions:{usePreset:"react",plugins:[],presets:[]},runTsChecker:!0,lessOptions:{},postcssOptions:{cssnanoOptions:{}},pixelOptions:{rootValue:{px:100,rpx:1},outputUnit:"rem"},modularImports:[]},entryMap:{},multiHtmlCdn:{},multiHtmlCdnEnvResolver:function cdnResolver(){},needVerifyPackages:{},packageInstallChecker:{enabled:!1,detectModules:["@dimjs/*"],throwError:!1,showAllInstalledGraph:!0},maxProcesses:"80%",ci:{basedBranch:"master"}};
1
+ export const defaultEvolveOptions = {
2
+ projectCwd: process.cwd(),
3
+ projectVirtualPath: 'flatjs/evolve',
4
+ rejectWarnings: false,
5
+ devServer: {
6
+ autoOpen: true,
7
+ mockOptions: {
8
+ mockBaseDir: 'mocks',
9
+ },
10
+ clientOverlay: {
11
+ errors: true,
12
+ warnings: false,
13
+ },
14
+ middlewares: [],
15
+ watchOptions: {
16
+ poll: 1000,
17
+ ignored: /node_modules/,
18
+ aggregateTimeout: 500,
19
+ },
20
+ defaultServeGlobalData: () => Promise.resolve({}),
21
+ },
22
+ webpack: {
23
+ // The default is es5
24
+ target: ['web', 'es5'],
25
+ plugins: [],
26
+ ruleSets: [],
27
+ publicPath: 'auto',
28
+ externals: {
29
+ vue: 'Vue',
30
+ react: 'React',
31
+ // eslint-disable-next-line @typescript-eslint/naming-convention
32
+ 'react-dom': 'ReactDOM',
33
+ },
34
+ outputDir: 'public',
35
+ enableBundleHashName: true,
36
+ },
37
+ pluginOptions: {},
38
+ loaderOptions: {
39
+ assetDataUrlMaxSize: 4 * 1024,
40
+ babelOptions: {
41
+ // 默认值的必须使用object类型, 如果使用函数, 会导致merge默认值失败.
42
+ usePreset: 'react',
43
+ plugins: [],
44
+ presets: [],
45
+ },
46
+ runTsChecker: true,
47
+ lessOptions: {},
48
+ postcssOptions: {
49
+ cssnanoOptions: {},
50
+ },
51
+ pixelOptions: {
52
+ rootValue: { px: 100, rpx: 1 },
53
+ outputUnit: 'rem',
54
+ },
55
+ // Always defined in evolve.config.js
56
+ modularImports: [],
57
+ },
58
+ entryMap: {},
59
+ // The configurations for plugin `@flatjs/evolve`, `multi-cdn-plugin`
60
+ multiHtmlCdn: {},
61
+ // Do not use arrow function here.
62
+ multiHtmlCdnEnvResolver: function cdnResolver() {
63
+ return undefined;
64
+ },
65
+ needVerifyPackages: {},
66
+ packageInstallChecker: {
67
+ enabled: false,
68
+ detectModules: ['@dimjs/*'],
69
+ throwError: false,
70
+ showAllInstalledGraph: true,
71
+ },
72
+ maxProcesses: '80%',
73
+ /**
74
+ * CI default configurations.
75
+ */
76
+ ci: {
77
+ basedBranch: 'master',
78
+ },
79
+ };
@@ -1 +1,4 @@
1
- import{defineConfig as myDefineConfig}from"@flatjs/common";export const defineConfig=f=>myDefineConfig(f);
1
+ import { defineConfig as myDefineConfig, } from '@flatjs/common';
2
+ export const defineConfig = (userConfig) => {
3
+ return myDefineConfig(userConfig);
4
+ };
@@ -1 +1 @@
1
- export*from"./define-config.js";
1
+ export * from './define-config.js';
@@ -1 +1,47 @@
1
- import{join}from"node:path";import WebpackDevServer from"webpack-dev-server";export const addCompilerToDevServer=(e,r,t,o)=>{const{projectCwd:p,devServer:s}=o,l=new WebpackDevServer({server:{type:s?.https?"https":"http",options:{...s?.https}},open:!1,compress:!0,port:t,hot:r,liveReload:!r,allowedHosts:"all",static:{directory:`${join(p,"/public")}`},headers:{"Access-Control-Allow-Origin":"*"},client:{progress:!0,overlay:s?.clientOverlay}},e);return new Promise(((e,r)=>{l.startCallback((t=>{if(t)return r(t);e(!0)}))}))};
1
+ import { join } from 'node:path';
2
+ import WebpackDevServer from 'webpack-dev-server';
3
+ /**
4
+ * Integrated webpack-dev-server with `mock` server together
5
+ * @param compiler Webpack compiler(s)
6
+ * @param enableHmr Value indicates if we need to liveReload or `HMR`
7
+ * @param devPort The port number of `@flatjs/mock`
8
+ * @param evolveOptions The configuration of `@flatjs/evolve` (FlatEvolveOptions)
9
+ */
10
+ export const addCompilerToDevServer = (compiler, enableHmr, devPort, evolveOptions) => {
11
+ const { projectCwd, devServer } = evolveOptions;
12
+ const server = new WebpackDevServer({
13
+ server: {
14
+ type: devServer?.https ? 'https' : 'http',
15
+ options: {
16
+ // Load https
17
+ ...devServer?.https,
18
+ },
19
+ },
20
+ open: false,
21
+ compress: true,
22
+ port: devPort,
23
+ hot: enableHmr,
24
+ liveReload: !enableHmr,
25
+ // Enable firewall or set hosts that are allowed to access the dev server.
26
+ allowedHosts: 'all',
27
+ static: {
28
+ directory: `${join(projectCwd, '/public')}`,
29
+ },
30
+ headers: {
31
+ // eslint-disable-next-line @typescript-eslint/naming-convention
32
+ 'Access-Control-Allow-Origin': '*',
33
+ },
34
+ client: {
35
+ progress: true,
36
+ overlay: devServer?.clientOverlay,
37
+ },
38
+ }, compiler);
39
+ return new Promise((resolve, reject) => {
40
+ server.startCallback((err) => {
41
+ if (err) {
42
+ return reject(err);
43
+ }
44
+ resolve(true);
45
+ });
46
+ });
47
+ };
@@ -1 +1,11 @@
1
- import{createPageMiddleware,createPublicAssetsMiddleware}from"./middlewares/index.js";export const createAppPageRoute=(e,a,r,t,s)=>{const{devServer:d}=s;a.use("/pages",...createPageMiddleware(r,d?.mockOptions?.apiContext||"api",t,s)),a.use("*",createPublicAssetsMiddleware(e))};
1
+ import { createPageMiddleware, createPublicAssetsMiddleware, } from './middlewares/index.js';
2
+ /**
3
+ * Add route `/pages`, `*` to main web-server
4
+ */
5
+ export const createAppPageRoute = (projectCwd, app, devHostUri, servedDevServerEntries, evolveOptions) => {
6
+ const { devServer } = evolveOptions;
7
+ // Attach request handlers for context `/page/*`
8
+ app.use('/pages', ...createPageMiddleware(devHostUri, devServer?.mockOptions?.apiContext || 'api', servedDevServerEntries, evolveOptions));
9
+ // handle all no-matched page request.
10
+ app.use('*', createPublicAssetsMiddleware(projectCwd));
11
+ };
@@ -1 +1,51 @@
1
- import{relative}from"node:path";import{chalk,logger,mergeOptions,urlJoin}from"@flatjs/common";import webpack from"webpack";import{loadWebpackConfig}from"../create-webpack/load-webpack-config.js";import{shouldEnableReactFastRefresh}from"../helpers/should-enable-react-fast-refresh.js";import{splitToMultiCompilerConfigs}from"../helpers/split-to-multi-compiler.js";import{addCompilerToDevServer}from"./add-compiler-to-dev-server.js";export const createDevServerCompilerTasks=async(e,o,r,t)=>{const i=[];for(const[a,n]of Object.entries(r)){const l=n.entryConfig,s=l.options?.moduleFederation,p=shouldEnableReactFastRefresh(!0,[a,l],t);(s?.remotes||[]).forEach((e=>{e.endpoint=e=>{const o=r[e];if(!o)throw new Error(`No servedDevServerEntry found via "${e}"`);return urlJoin(o?.devServerHostUri,["/public"])}}));const{devServerPort:c,devServerHostUri:m}=r[a],f={[a]:l},d=urlJoin(m,["public"]),v=await loadWebpackConfig("development",f,mergeOptions(t,{webpack:{publicPath:d}})),h=webpack(splitToMultiCompilerConfigs(f,v,t)[0]);i.push(addCompilerToDevServer(h,p,c,t));const g=h.name||"";h.hooks.invalid.tap("fileChange",(o=>{const r=relative(e,o||"");logger.info(`file change ➩ ${chalk(["cyan"])(r)}`,g)})),h.hooks.done.tap("compileDone",(()=>{logger.info(`debug page ➩ ${chalk(["cyan"])(o)}`,g)}))}return i};
1
+ import { relative } from 'node:path';
2
+ import { chalk, logger, mergeOptions, urlJoin } from '@flatjs/common';
3
+ import webpack from 'webpack';
4
+ import { loadWebpackConfig } from '../create-webpack/load-webpack-config.js';
5
+ import { shouldEnableReactFastRefresh } from '../helpers/should-enable-react-fast-refresh.js';
6
+ import { splitToMultiCompilerConfigs } from '../helpers/split-to-multi-compiler.js';
7
+ import { addCompilerToDevServer } from './add-compiler-to-dev-server.js';
8
+ export const createDevServerCompilerTasks = async (projectCwd, mainPage, servedDevServerEntries, evolveOptions) => {
9
+ const serveTaks = [];
10
+ for (const [entryName, servedDevServerEntry] of Object.entries(servedDevServerEntries)) {
11
+ const itemEntryConfig = servedDevServerEntry.entryConfig;
12
+ const moduleFederation = itemEntryConfig.options?.moduleFederation;
13
+ const enabledHmr = shouldEnableReactFastRefresh(true, [entryName, itemEntryConfig], evolveOptions);
14
+ const moduleFederationRemotes = moduleFederation?.remotes || [];
15
+ moduleFederationRemotes.forEach((remote) => {
16
+ // Dynamic construct remote endpoint as hostUri
17
+ remote.endpoint = (shortName) => {
18
+ const servedDevServerEntry = servedDevServerEntries[shortName];
19
+ if (!servedDevServerEntry) {
20
+ throw new Error(`No servedDevServerEntry found via "${shortName}"`);
21
+ }
22
+ return urlJoin(servedDevServerEntry?.devServerHostUri, ['/public']);
23
+ };
24
+ });
25
+ const { devServerPort, devServerHostUri } = servedDevServerEntries[entryName];
26
+ const singleEvolveEntryMap = {
27
+ // e.g. `home`
28
+ [entryName]: itemEntryConfig,
29
+ };
30
+ // e.g. `http://dev.flatjs.com:3002/public/`
31
+ const servePublicPath = urlJoin(devServerHostUri, ['public']);
32
+ const webpackConfig = await loadWebpackConfig('development', singleEvolveEntryMap, mergeOptions(evolveOptions, {
33
+ webpack: {
34
+ publicPath: servePublicPath,
35
+ },
36
+ }));
37
+ const compiler = webpack(splitToMultiCompilerConfigs(singleEvolveEntryMap, webpackConfig, evolveOptions)[0]);
38
+ serveTaks.push(
39
+ // create webpack dev server instance.
40
+ addCompilerToDevServer(compiler, enabledHmr, devServerPort, evolveOptions));
41
+ const title = compiler.name || '';
42
+ compiler.hooks.invalid.tap('fileChange', (fileName) => {
43
+ const relativeFileName = relative(projectCwd, fileName || '');
44
+ logger.info(`file change ➩ ${chalk(['cyan'])(relativeFileName)}`, title);
45
+ });
46
+ compiler.hooks.done.tap('compileDone', () => {
47
+ logger.info(`debug page ➩ ${chalk(['cyan'])(mainPage)}`, title);
48
+ });
49
+ }
50
+ return serveTaks;
51
+ };
@@ -1 +1,27 @@
1
- import{mergeOptions}from"@flatjs/common";import{prepareMockDomain}from"@flatjs/mock";import{normalizeEvolveEntryName}from"../helpers/normalize-entry-map.js";export const createDevServerEntries=async(r,e,o)=>{const{devServer:t,projectVirtualPath:n}=o,m={};let a=r;for(const[r,o]of Object.entries(e)){a+=1;const{mockPort:e,hostUri:i}=await prepareMockDomain(mergeOptions(t?.mockOptions||{},{port:a})),s=normalizeEvolveEntryName(r,n);m[r]={entryConfig:o,devServerPort:e,devServerHostUri:i,normalizedEntryName:s}}return m};
1
+ import { mergeOptions } from '@flatjs/common';
2
+ import { prepareMockDomain } from '@flatjs/mock';
3
+ import { normalizeEvolveEntryName } from '../helpers/normalize-entry-map.js';
4
+ export const createDevServerEntries = async (startPort, servedEntries, evolveOptions) => {
5
+ const { devServer, projectVirtualPath } = evolveOptions;
6
+ const servedDevServerEntries = {};
7
+ // https://github.com/webpack/webpack-dev-server/issues/2692
8
+ // For `webpack-dev-server@4.0.0` we should run dev server on each compiler
9
+ let makeLastestPort = startPort;
10
+ // Prepare devServer ports for each served entry.
11
+ for (const [entryName, entryConfig] of Object.entries(servedEntries)) {
12
+ makeLastestPort = makeLastestPort + 1;
13
+ // Create individual devPort for each compiler here.
14
+ const { mockPort: devServerPort, hostUri: devServerHostUri } = await prepareMockDomain(mergeOptions(devServer?.mockOptions || {}, {
15
+ port: makeLastestPort,
16
+ }));
17
+ // entryName: `home` should be normallized to ${`projectVirtualPath`}/home
18
+ const normalizedEntryName = normalizeEvolveEntryName(entryName, projectVirtualPath);
19
+ servedDevServerEntries[entryName] = {
20
+ entryConfig,
21
+ devServerPort,
22
+ devServerHostUri,
23
+ normalizedEntryName,
24
+ };
25
+ }
26
+ return servedDevServerEntries;
27
+ };
@@ -1 +1,23 @@
1
- import https from"node:https";import{prepareMockDomain}from"@flatjs/mock";import express from"express";export const createDevServer=async e=>{const r=express(),t=e.devServer?.mockOptions,{mockPort:o,hostUri:s}=await prepareMockDomain(t||{});return new Promise((t=>{const p=e.devServer?.https?https.createServer(e.devServer?.https,r):r;r.set("hostUri",s),p.listen(o,(()=>{t({app:r,devHostUri:s,devPort:o})}))}))};
1
+ import https from 'node:https';
2
+ import { prepareMockDomain } from '@flatjs/mock';
3
+ import express from 'express';
4
+ export const createDevServer = async (evolveOptions) => {
5
+ const app = express();
6
+ const mockOptions = evolveOptions.devServer?.mockOptions;
7
+ const { mockPort, hostUri } = await prepareMockDomain(mockOptions || {});
8
+ return new Promise((resolve) => {
9
+ // Https
10
+ const httpsServer = evolveOptions.devServer?.https
11
+ ? https.createServer(evolveOptions.devServer?.https, app)
12
+ : app;
13
+ // Attach hostUri to application instance without last slash `/`.
14
+ app.set('hostUri', hostUri);
15
+ httpsServer.listen(mockPort, () => {
16
+ resolve({
17
+ app,
18
+ devHostUri: hostUri,
19
+ devPort: mockPort,
20
+ });
21
+ });
22
+ });
23
+ };
@@ -1 +1,6 @@
1
- export*from"./middlewares/index.js";export*from"./add-compiler-to-dev-server.js";export*from"./create-dev-server.js";export*from"./create-app-page-route.js";export*from"./create-dev-server-entries.js";export*from"./create-dev-server-compiler-tasks.js";
1
+ export * from './middlewares/index.js';
2
+ export * from './add-compiler-to-dev-server.js';
3
+ export * from './create-dev-server.js';
4
+ export * from './create-app-page-route.js';
5
+ export * from './create-dev-server-entries.js';
6
+ export * from './create-dev-server-compiler-tasks.js';
@@ -1 +1,164 @@
1
- import{existsSync,readFileSync}from"node:fs";import{isAbsolute,join}from"node:path";import{ensureSlash,urlJoin}from"@flatjs/common";import _ from"lodash";import{allowPx2remForModule}from"../../helpers/allow-px2rem-for-module.js";import{getHtmlPluginConfig}from"../../helpers/get-html-plugin-config.js";import{getPackageDir}from"../../helpers/get-pacakge-dir.js";import{normalizeEvolveEntryName}from"../../helpers/normalize-entry-map.js";import{injectFederationScripts}from"../../helpers/script-injects.js";const getPageMainHtml=async(e,t,l)=>{const r=getPackageDir(),o=readFileSync(join(r,"./templates/main.html"),"utf-8"),a=[],i=l.projectVirtualPath.replace(/^\//,"");for(const[r,o]of Object.entries(l.entryMap)){const l=o.options?.servePageMainLinkFn||(e=>e),n=Object.keys(e).includes(r),s=normalizeEvolveEntryName(r,i),m=urlJoin(t,["pages",s],{env:"me"});a.push({name:r.replace(i,"").replace(/^\//,""),link:l(m,{hostUri:t,entryName:r,virtualPath:i}),flagText:n?"serve":"static",isServed:n?1:0})}const n={title:"@flatjs/evolve",modules:a.sort(((e,t)=>t.isServed-e.isServed))};return _.template(o)(n)},getPageModuleHtml=async(e,t,l,r,o)=>{const{entryMap:a,projectVirtualPath:i}=o,n=Object.keys(a).sort(((e,t)=>t.length-e.length)),s=getPackageDir(),m=n.find((e=>{const l=normalizeEvolveEntryName(e,i);return ensureSlash(t.path.replace(/^\//,""),!0).startsWith(ensureSlash(l,!0))}));if(!m){const e=readFileSync(join(s,"./templates/module-404.html"),"utf-8");return _.template(e)({title:"404 Not Found",errorMeta:[{name:"@flatjs/evolve workspace",value:s},{name:"served entry names",value:JSON.stringify(n)},{name:"module path",value:`${t.path}`}]})}const p=normalizeEvolveEntryName(m,i),c=a[m],d=c.options,u=e[m],g=u?.devServerHostUri||l,f=d?.serveModuleTemplate||"./templates/module.html",v=join(o.projectCwd,"./templates/module.html"),h=readFileSync(isAbsolute(f)?f:existsSync(v)?v:join(s,"./templates/module.html"),"utf-8"),S=o.devServer,y=S?.defaultServeGlobalData?await S.defaultServeGlobalData(c,l):{},j={title:getHtmlPluginConfig("title","development",d?.title),favicon:getHtmlPluginConfig("favicon","development",d?.favicon),viewport:allowPx2remForModule([m,c],o)?getHtmlPluginConfig("viewport","development",d?.viewport):"",headBeforeHtmlTags:getHtmlPluginConfig("headBeforeHtmlTags","development",d?.headBeforeHtmlTags),inlineScripts:getHtmlPluginConfig("inlineScripts","development",d?.inlineScripts),headBeforeStyles:getHtmlPluginConfig("headBeforeStyles","development",d?.headBeforeStyles),headBeforeScripts:getHtmlPluginConfig("headBeforeScripts","development",d?.headBeforeScripts),bodyAfterScripts:getHtmlPluginConfig("bodyAfterScripts","development",d?.bodyAfterScripts),moduleFederationScripts:injectFederationScripts({me:[urlJoin(l,["public"])]},o.multiHtmlCdnEnvResolver),global:{hostUrl:l,apiBase:urlJoin(l,[r]),virtualPath:join("/pages",i),moduleName:m.replace(i,"").replace(/^\//,""),...y,...d?.serveGlobalData||{}},styles:[urlJoin(g,[join("public",p,"bundle.css")])],scripts:[urlJoin(g,[join("public",p,"bundle.js")])]};return _.template(h)(j)};export const createPageMiddleware=(e,t,l,r)=>(r.devServer?.middlewares||[]).concat((async(o,a)=>{let i;i="/"===o.path?await getPageMainHtml(l,e,r):await getPageModuleHtml(l,o,e,t,r),a.send(i)}));
1
+ import { existsSync, readFileSync } from 'node:fs';
2
+ import { isAbsolute, join } from 'node:path';
3
+ import { ensureSlash, urlJoin } from '@flatjs/common';
4
+ import _ from 'lodash';
5
+ import { allowPx2remForModule } from '../../helpers/allow-px2rem-for-module.js';
6
+ import { getHtmlPluginConfig, } from '../../helpers/get-html-plugin-config.js';
7
+ import { getPackageDir } from '../../helpers/get-pacakge-dir.js';
8
+ import { normalizeEvolveEntryName } from '../../helpers/normalize-entry-map.js';
9
+ import { injectFederationScripts } from '../../helpers/script-injects.js';
10
+ const getPageMainHtml = async (servedDevServerEntries, devHostUri, evolveOptions) => {
11
+ const evolveCwd = getPackageDir();
12
+ const templateStr = readFileSync(join(evolveCwd, './templates/main.html'), 'utf-8');
13
+ const sortedModules = [];
14
+ const virtualPath = evolveOptions.projectVirtualPath.replace(/^\//, '');
15
+ for (const [entryName, entryContent] of Object.entries(evolveOptions.entryMap)) {
16
+ // Allow customized page main link.
17
+ const servePageMainLinkFn = entryContent.options?.servePageMainLinkFn || ((link) => link);
18
+ // `home`, servedDevServerEntries[key] => `home`
19
+ const isServedEntry = Object.keys(servedDevServerEntries).includes(entryName);
20
+ // `flatjs/evolve/home`
21
+ const normalizedEntryName = normalizeEvolveEntryName(entryName, virtualPath);
22
+ const linkHref = urlJoin(devHostUri, ['pages', normalizedEntryName], {
23
+ env: 'me',
24
+ });
25
+ sortedModules.push({
26
+ name: entryName.replace(virtualPath, '').replace(/^\//, ''),
27
+ link: servePageMainLinkFn(linkHref, {
28
+ hostUri: devHostUri,
29
+ entryName,
30
+ virtualPath,
31
+ }),
32
+ flagText: isServedEntry ? 'serve' : 'static',
33
+ isServed: isServedEntry ? 1 : 0,
34
+ });
35
+ }
36
+ const templateData = {
37
+ title: '@flatjs/evolve',
38
+ modules: sortedModules.sort((a, b) => {
39
+ return b.isServed - a.isServed;
40
+ }),
41
+ };
42
+ return _.template(templateStr)(templateData);
43
+ };
44
+ const getPageModuleHtml = async (servedDevServerEntries, req, devHostUri, apiContext, evolveOptions) => {
45
+ const { entryMap, projectVirtualPath } = evolveOptions;
46
+ // normalize to ['a/b','a/b/c','inn/app/transfer_list','inn/app/transfer']
47
+ const entryNames = Object.keys(entryMap).sort((a, b) => b.length - a.length);
48
+ const evolveCwd = getPackageDir();
49
+ const currEntry = entryNames.find((entryName) => {
50
+ const normalizedEntryName = normalizeEvolveEntryName(entryName, projectVirtualPath);
51
+ return ensureSlash(req.path.replace(/^\//, ''), true).startsWith(ensureSlash(normalizedEntryName, true));
52
+ });
53
+ if (!currEntry) {
54
+ const notFoundTemplateStr = readFileSync(join(evolveCwd, `./templates/module-404.html`), 'utf-8');
55
+ return _.template(notFoundTemplateStr)({
56
+ title: '404 Not Found',
57
+ errorMeta: [
58
+ {
59
+ name: `@flatjs/evolve workspace`,
60
+ value: evolveCwd,
61
+ },
62
+ {
63
+ name: `served entry names`,
64
+ value: JSON.stringify(entryNames),
65
+ },
66
+ // eslint-disable-next-line @typescript-eslint/restrict-template-expressions
67
+ { name: `module path`, value: `${req.path}` },
68
+ ],
69
+ });
70
+ }
71
+ const normalizedCurrEntry = normalizeEvolveEntryName(currEntry, projectVirtualPath);
72
+ const currEntryItem = entryMap[currEntry];
73
+ const currEntryOption = currEntryItem.options;
74
+ // currEntry: `home`
75
+ const currDevServerEntry = servedDevServerEntries[currEntry];
76
+ // Maybe No currEntry found in servedDevServerEntries, use default `hostUri`, e.g. `static` mode.
77
+ const devServerHostUri = currDevServerEntry?.devServerHostUri || devHostUri;
78
+ const moduleTemplate =
79
+ // eslint-disable-next-line sonarjs/no-duplicate-string
80
+ currEntryOption?.serveModuleTemplate || './templates/module.html';
81
+ const projectHostedModuleTemplate = join(evolveOptions.projectCwd, './templates/module.html');
82
+ const templateStr = readFileSync(isAbsolute(moduleTemplate)
83
+ ? moduleTemplate
84
+ : existsSync(projectHostedModuleTemplate)
85
+ ? projectHostedModuleTemplate
86
+ : join(evolveCwd, './templates/module.html'), 'utf-8');
87
+ const devServer = evolveOptions.devServer;
88
+ const defaultGlobalData = devServer?.defaultServeGlobalData
89
+ ? await devServer.defaultServeGlobalData(currEntryItem, devHostUri)
90
+ : {};
91
+ const configData = {
92
+ mode: 'development',
93
+ // FIXME: always use `devHostUri` as served local `cdn`, if you want to serve `anther` module
94
+ // you need to generate cdn path manually.
95
+ envCdn: urlJoin(devHostUri, ['public']),
96
+ };
97
+ const templateData = {
98
+ // title
99
+ title: getHtmlPluginConfig('title', configData, currEntryOption?.title),
100
+ // favicon
101
+ favicon: getHtmlPluginConfig('favicon', configData, currEntryOption?.favicon),
102
+ // `allowPx2rem` default is true
103
+ viewport: allowPx2remForModule([currEntry, currEntryItem], evolveOptions)
104
+ ? getHtmlPluginConfig('viewport', configData, currEntryOption?.viewport)
105
+ : '',
106
+ // The customized html tags should be inject to <header />
107
+ headBeforeHtmlTags: getHtmlPluginConfig('headBeforeHtmlTags', configData, currEntryOption?.headBeforeHtmlTags),
108
+ // Allow us customized inline scripts into compiled html template.
109
+ inlineScripts: getHtmlPluginConfig('inlineScripts', configData, currEntryOption?.inlineScripts),
110
+ // The ordered styles will be injected start of html head.
111
+ headBeforeStyles: getHtmlPluginConfig('headBeforeStyles', configData, currEntryOption?.headBeforeStyles),
112
+ // The ordered scripts will be injected before html head.
113
+ headBeforeScripts: getHtmlPluginConfig('headBeforeScripts', configData, currEntryOption?.headBeforeScripts),
114
+ // The ordered scripts will be injected end of html body.
115
+ bodyAfterScripts: getHtmlPluginConfig('bodyAfterScripts', configData, currEntryOption?.bodyAfterScripts),
116
+ // Module Federation, Only for `static` mode, `serve` mode it will use entryItemConfig.endpoint()
117
+ moduleFederationScripts: injectFederationScripts({
118
+ me: [urlJoin(devHostUri, ['public'])],
119
+ }, evolveOptions.multiHtmlCdnEnvResolver),
120
+ // The global data.
121
+ global: {
122
+ hostUrl: devHostUri,
123
+ apiBase: urlJoin(devHostUri, [apiContext]),
124
+ virtualPath: join(`/pages`, projectVirtualPath),
125
+ moduleName: currEntry.replace(projectVirtualPath, '').replace(/^\//, ''),
126
+ ...defaultGlobalData,
127
+ ...(currEntryOption?.serveGlobalData || {}),
128
+ },
129
+ styles: [
130
+ urlJoin(devServerHostUri, [
131
+ join('public', normalizedCurrEntry, 'bundle.css'),
132
+ ]),
133
+ ],
134
+ scripts: [
135
+ urlJoin(devServerHostUri, [
136
+ join('public', normalizedCurrEntry, 'bundle.js'),
137
+ ]),
138
+ ],
139
+ };
140
+ return _.template(templateStr)(templateData);
141
+ };
142
+ /**
143
+ * A middleware to proxy the page modules template.
144
+ * @example `http://dev.flatjs.com:3001/pages`
145
+ * @param mode The mode of this dev server instance.
146
+ * @param hostUri The main host base url.
147
+ * @param apiContext apiBase e.g. `api`
148
+ * @param servedDevServerEntries The served webpack entries
149
+ * @param forPageMiddlewares Allow us provider customized middlewares for `page`, `modules`
150
+ * @param evolveOptions The evolve config options
151
+ */
152
+ export const createPageMiddleware = (devHostUri, apiContext, servedDevServerEntries, evolveOptions) => {
153
+ const handler = async (req, res) => {
154
+ let html;
155
+ if (req.path === '/') {
156
+ html = await getPageMainHtml(servedDevServerEntries, devHostUri, evolveOptions);
157
+ }
158
+ else {
159
+ html = await getPageModuleHtml(servedDevServerEntries, req, devHostUri, apiContext, evolveOptions);
160
+ }
161
+ res.send(html);
162
+ };
163
+ return (evolveOptions.devServer?.middlewares || []).concat(handler);
164
+ };
@@ -1 +1,25 @@
1
- import{extname,join}from"node:path";import{fileWalk}from"@armit/file-utility";export const createPublicAssetsMiddleware=e=>async(i,s)=>{const t=i.baseUrl;if(t.startsWith("/public")){const i=await fileWalk(join("public/","**/*.{js,css}"),{cwd:e}),a=extname(t),l=i.find((e=>extname(e)===a&&-1!==e.indexOf(t.replace(/\.(?:js|css)$/,""))));l?s.sendFile(l):s.sendFile(join(e,t))}else s.redirect("/pages")};
1
+ import { extname, join } from 'node:path';
2
+ import { fileWalk } from '@armit/file-utility';
3
+ export const createPublicAssetsMiddleware = (projectCwd) => async (req, res) => {
4
+ const baseUrl = req.baseUrl;
5
+ // exclude `/public` leave it fallback into webpack hot server
6
+ if (!baseUrl.startsWith('/public')) {
7
+ res.redirect('/pages');
8
+ }
9
+ else {
10
+ const publicFiles = await fileWalk(join('public/', '**/*.{js,css}'), {
11
+ cwd: projectCwd,
12
+ });
13
+ const extension = extname(baseUrl);
14
+ const matchedBundleFile = publicFiles.find((file) => {
15
+ return (extname(file) === extension &&
16
+ file.indexOf(baseUrl.replace(/\.(?:js|css)$/, '')) !== -1);
17
+ });
18
+ if (matchedBundleFile) {
19
+ res.sendFile(matchedBundleFile);
20
+ }
21
+ else {
22
+ res.sendFile(join(projectCwd, baseUrl));
23
+ }
24
+ }
25
+ };
@@ -1 +1,2 @@
1
- export*from"./create-page-middleware.js";export*from"./create-public-assets-middleware.js";
1
+ export * from './create-page-middleware.js';
2
+ export * from './create-public-assets-middleware.js';
@@ -1 +1,10 @@
1
- export class EvolveBuildError extends Error{constructor(r,e){let o=r;e&&(o+=": "+JSON.stringify(e)),super(o),this.code=r}}
1
+ export class EvolveBuildError extends Error {
2
+ constructor(code, messages) {
3
+ let message = code;
4
+ if (messages) {
5
+ message += ': ' + JSON.stringify(messages);
6
+ }
7
+ super(message);
8
+ this.code = code;
9
+ }
10
+ }
@@ -1 +1,6 @@
1
- export const allowPx2remForModule=(o,e)=>{const l=e?.loaderOptions?.pixelOptions;return!!((o&&o[1]?.options?.allowPx2rem)??l)};
1
+ export const allowPx2remForModule = (entryItem, evolveOptions) => {
2
+ // Global settings for `AllowPx2Rem`
3
+ const globalAllowPx2Rem = evolveOptions?.loaderOptions?.pixelOptions;
4
+ const currItemPx2Rem = (entryItem && entryItem[1]?.options?.allowPx2rem) ?? globalAllowPx2Rem;
5
+ return !!currItemPx2Rem;
6
+ };
@@ -1 +1,23 @@
1
- import{normalizeEvolveEntryName}from"./normalize-entry-map.js";export const assertOnlySingleEntryItem=(e,r)=>{if(Object.keys(e).length>1)throw new Error("Only single one entry map support right now for `serve`, `build`!");let t;for(const[r,o]of Object.entries(e)){t=[r,o];break}if(!t)throw new Error('No entry map found while "serve", "build" process!');const[o,n]=t;return[normalizeEvolveEntryName(o,r.projectVirtualPath),n]};
1
+ import { normalizeEvolveEntryName } from './normalize-entry-map.js';
2
+ /**
3
+ * Only fetch single one entry map once `serve`,`build` recycle.
4
+ * @returns
5
+ */
6
+ export const assertOnlySingleEntryItem = (entryMap, evolveOptions) => {
7
+ if (Object.keys(entryMap).length > 1) {
8
+ throw new Error('Only single one entry map support right now for `serve`, `build`!');
9
+ }
10
+ let result = undefined;
11
+ for (const [entryChunkName, entryItem] of Object.entries(entryMap)) {
12
+ result = [entryChunkName, entryItem];
13
+ break;
14
+ }
15
+ if (!result) {
16
+ throw new Error(`No entry map found while "serve", "build" process!`);
17
+ }
18
+ const [entryName, entryConfig] = result;
19
+ // Make sure that we have correct `virtualPath` for each webpack `entry`
20
+ const normalizedEntryName = normalizeEvolveEntryName(entryName, evolveOptions.projectVirtualPath);
21
+ `entry`;
22
+ return [normalizedEntryName, entryConfig];
23
+ };
@@ -1 +1,21 @@
1
- import{arrayChunk}from"@flatjs/common";export const chunkEntryMap=(r,o=2)=>{const n=Object.keys(r),t=arrayChunk(n,o),c=[];for(const o of t){const n=o.reduce(((o,n)=>({...o,[n]:r[n]})),{});c.push(n)}return c};
1
+ import { arrayChunk } from '@flatjs/common';
2
+ /**
3
+ * Split entryMap into multi entryMap with a `size`
4
+ * @param entryMap
5
+ * @param size
6
+ */
7
+ export const chunkEntryMap = (entryMap, size = 2) => {
8
+ const keys = Object.keys(entryMap);
9
+ const entryKeyChunks = arrayChunk(keys, size);
10
+ const finalEntryMaps = [];
11
+ for (const keys of entryKeyChunks) {
12
+ const chunkMap = keys.reduce((prev, curr) => {
13
+ return {
14
+ ...prev,
15
+ [curr]: entryMap[curr],
16
+ };
17
+ }, {});
18
+ finalEntryMaps.push(chunkMap);
19
+ }
20
+ return finalEntryMaps;
21
+ };
@@ -1 +1,6 @@
1
- export const enableBundleHashNameForModule=(e,a)=>{const n=e.webpack?.enableBundleHashName;return!!(a?.enableBundleHashName??n)};
1
+ export const enableBundleHashNameForModule = (evolveOptions, entryItemOption) => {
2
+ // Global settings for `enableBundleHashName`
3
+ const globalEnabledStatus = evolveOptions.webpack?.enableBundleHashName;
4
+ const bundleHashNameEnabled = entryItemOption?.enableBundleHashName ?? globalEnabledStatus;
5
+ return !!bundleHashNameEnabled;
6
+ };
@@ -5,7 +5,7 @@ import { type EvolveEntryMap } from '../types/types-entry-map.js';
5
5
  * @param modules `home;mine;`
6
6
  * @returns activedEntries
7
7
  */
8
- export declare const filterActivedEntriesByModule: (definedEntries: EvolveEntryMap, modules: string[]) => EvolveEntryMap;
8
+ export declare const filterActivedEntriesByModule: (definedEntries: EvolveEntryMap, modules: Array<string | RegExp>) => EvolveEntryMap;
9
9
  /**
10
10
  * Filter to find actived entry input by absolute entry filepath
11
11
  * @param projectCwd
@@ -1 +1,41 @@
1
- import{arraysIntersect,normalizeSemicolonFilterParts}from"@flatjs/common";import{resolveEntryMapInputFiles}from"./resolve-entry-map-input-files.js";export const filterActivedEntriesByModule=(t,e)=>{const r=normalizeSemicolonFilterParts(e),n={};for(const[e,o]of Object.entries(t))r.find((t=>new RegExp(`${t}`).test(e)))&&(n[e]=o);return n};export const filterActivedEntriesByEntryInputs=async(t,e,r)=>{const n={};for(const[o,s]of Object.entries(e)){const e=await resolveEntryMapInputFiles(t,{[o]:s});arraysIntersect(e,r)&&(n[o]=s)}return n};
1
+ import { arraysIntersect, normalizeSemicolonFilterParts } from '@flatjs/common';
2
+ import { resolveEntryMapInputFiles } from './resolve-entry-map-input-files.js';
3
+ /**
4
+ * Filter to find actived entry input by entry name filter.
5
+ * @param definedEntries
6
+ * @param modules `home;mine;`
7
+ * @returns activedEntries
8
+ */
9
+ export const filterActivedEntriesByModule = (definedEntries, modules) => {
10
+ const patterns = normalizeSemicolonFilterParts(modules);
11
+ const newActivedEntries = {};
12
+ for (const [entryKey, itemConfig] of Object.entries(definedEntries)) {
13
+ const matched = patterns.find((m) => {
14
+ const testRegExp = typeof m === 'string' ? new RegExp(`${m}`) : m;
15
+ return testRegExp.test(entryKey);
16
+ });
17
+ if (matched) {
18
+ newActivedEntries[entryKey] = itemConfig;
19
+ }
20
+ }
21
+ return newActivedEntries;
22
+ };
23
+ /**
24
+ * Filter to find actived entry input by absolute entry filepath
25
+ * @param projectCwd
26
+ * @param definedEntries
27
+ * @param entryInputs [`/xxxx/x/xxxx/src/home/index.tsx`]
28
+ * @returns activedEntries
29
+ */
30
+ export const filterActivedEntriesByEntryInputs = async (projectCwd, definedEntries, entryInputs) => {
31
+ const newActivedEntries = {};
32
+ for (const [entryKey, itemConfig] of Object.entries(definedEntries)) {
33
+ const entryAbsFiles = await resolveEntryMapInputFiles(projectCwd, {
34
+ [entryKey]: itemConfig,
35
+ });
36
+ if (arraysIntersect(entryAbsFiles, entryInputs)) {
37
+ newActivedEntries[entryKey] = itemConfig;
38
+ }
39
+ }
40
+ return newActivedEntries;
41
+ };
@@ -1 +1,23 @@
1
- export const currNow=()=>Date.now().toString();export const getBundleFileName=(t,n,e=!0)=>{const o="js"===t?".js":".css";return n?`bundle${o}`:e?`bundle[contenthash]${o}`:`bundle${o}?${Date.now().toString()}`};
1
+ /**
2
+ * Get current timestramp as `string`
3
+ */
4
+ export const currNow = () => Date.now().toString();
5
+ /**
6
+ * Generate bundle file name from rules
7
+ * 1. if `serveMode`, always return `bundle
8
+ * 2. else if `enableBundleHashName` always return `bundle[contenthash].{css,js}`
9
+ * 3. otherwise return `bundle.{css,js}?${currNow}`
10
+ * @param type `js` | `css`
11
+ * @param serveMode If we are run `serve` mode
12
+ * @param enableBundleHashName If we need to generate bundle file name with `[contenthash]`
13
+ */
14
+ export const getBundleFileName = (type, serveMode, enableBundleHashName = true) => {
15
+ const fileEndFix = type === 'js' ? '.js' : '.css';
16
+ if (serveMode) {
17
+ return `bundle${fileEndFix}`;
18
+ }
19
+ if (enableBundleHashName) {
20
+ return `bundle[contenthash]${fileEndFix}`;
21
+ }
22
+ return `bundle${fileEndFix}?${currNow()}`;
23
+ };