@flatjs/evolve 2.1.0-next.4 → 2.1.0-next.5
Sign up to get free protection for your applications and to get access to all the features.
- package/dist/constants.js +26 -1
- package/dist/create-webpack/create-externals.js +6 -1
- package/dist/create-webpack/create-optimization.js +41 -1
- package/dist/create-webpack/create-output.js +35 -1
- package/dist/create-webpack/create-performance.js +7 -1
- package/dist/create-webpack/create-plugins.js +77 -1
- package/dist/create-webpack/create-resolve.js +37 -1
- package/dist/create-webpack/create-rule-sets.js +19 -1
- package/dist/create-webpack/load-webpack-config.js +56 -1
- package/dist/create-webpack/resolve-public-path.js +15 -1
- package/dist/create-webpack/rule-sets/constants.js +3 -1
- package/dist/create-webpack/rule-sets/rule-assets.js +50 -1
- package/dist/create-webpack/rule-sets/rule-css.js +101 -1
- package/dist/create-webpack/rule-sets/rule-less.js +44 -1
- package/dist/create-webpack/rule-sets/rule-scripts.js +34 -1
- package/dist/create-webpack/rule-sets/rule-svg-icon.js +25 -1
- package/dist/create-webpack/rule-sets/rule-utils.js +10 -1
- package/dist/create-webpack/types.js +1 -1
- package/dist/default-options.js +84 -1
- package/dist/define-config/define-config.js +4 -1
- package/dist/define-config/index.js +1 -1
- package/dist/dev-server/add-compiler-to-dev-server.js +58 -1
- package/dist/dev-server/create-app-page-route.js +13 -1
- package/dist/dev-server/create-dev-server-compiler-tasks.js +52 -1
- package/dist/dev-server/create-dev-server-entries.js +27 -1
- package/dist/dev-server/create-dev-server.js +24 -1
- package/dist/dev-server/index.js +6 -1
- package/dist/dev-server/middlewares/create-page-middleware.js +33 -1
- package/dist/dev-server/middlewares/create-public-assets-middleware.js +25 -1
- package/dist/dev-server/middlewares/get-all-sorted-modules.js +24 -1
- package/dist/dev-server/middlewares/get-bundle-asset.js +7 -1
- package/dist/dev-server/middlewares/get-dev-server-host-uri.js +5 -1
- package/dist/dev-server/middlewares/get-hmr-runtime-chunks.js +14 -1
- package/dist/dev-server/middlewares/get-normalized-entry-name.js +14 -1
- package/dist/dev-server/middlewares/get-page-main-html.js +42 -1
- package/dist/dev-server/middlewares/get-page-module-html.js +120 -1
- package/dist/dev-server/middlewares/get-project-virtual-path.js +3 -1
- package/dist/dev-server/middlewares/get-runtime-manifest.js +25 -1
- package/dist/dev-server/middlewares/index.js +2 -1
- package/dist/dev-server/middlewares/types.js +1 -1
- package/dist/errors/evolve-build-error.js +10 -1
- package/dist/helpers/allow-px2rem-for-module.js +6 -1
- package/dist/helpers/assert-only-single-entry-item.js +23 -1
- package/dist/helpers/chunk-entry-map.js +21 -1
- package/dist/helpers/enable-bundle-hashname-for-module.js +6 -1
- package/dist/helpers/filter-actived-entries.js +42 -1
- package/dist/helpers/get-bundle-file-name.js +23 -1
- package/dist/helpers/get-git-root.js +4 -1
- package/dist/helpers/get-html-plugin-config.js +47 -1
- package/dist/helpers/get-max-process-tasks.js +7 -1
- package/dist/helpers/get-pacakge-dir.js +13 -1
- package/dist/helpers/index.js +17 -1
- package/dist/helpers/json-serializer.js +52 -1
- package/dist/helpers/merge-babel-options.js +45 -1
- package/dist/helpers/normalize-entry-map.js +38 -1
- package/dist/helpers/normalize-page-proxy.js +9 -1
- package/dist/helpers/normalize-resolve-alias.js +7 -1
- package/dist/helpers/open-page.js +15 -1
- package/dist/helpers/print-log.js +49 -1
- package/dist/helpers/refresh-evolve-mock-options.js +34 -1
- package/dist/helpers/resolve-entry-map-input-files.js +20 -1
- package/dist/helpers/script-injects.js +39 -1
- package/dist/helpers/should-enable-react-fast-refresh.js +10 -1
- package/dist/helpers/split-to-multi-compiler.js +32 -1
- package/dist/index.js +5 -1
- package/dist/load-config/index.js +1 -1
- package/dist/load-config/load-evolve-config.js +41 -1
- package/dist/load-config/types.js +1 -1
- package/dist/main/create-thread-worker.js +42 -1
- package/dist/main/env-verify.js +21 -1
- package/dist/main/get-worker-path.js +5 -1
- package/dist/main/index.js +4 -1
- package/dist/main/prepare-build.js +38 -1
- package/dist/main/prepare-serve.js +45 -1
- package/dist/main/prepare-static.js +30 -1
- package/dist/main/start-build-dynamic.js +157 -1
- package/dist/main/start-build-worker.js +46 -1
- package/dist/main/start-build.js +53 -1
- package/dist/main/start-one-entry-build.js +35 -1
- package/dist/main/start-serve.js +34 -1
- package/dist/main/start-static.js +19 -1
- package/dist/minimizer/create-minimizers.js +25 -1
- package/dist/minimizer/default-options.js +14 -1
- package/dist/minimizer/image-minimizer.js +65 -1
- package/dist/minimizer/index.js +1 -1
- package/dist/minimizer/terser-minimizer.js +15 -3
- package/dist/minimizer/types.js +1 -1
- package/dist/plugins/circular-dependency/circular-dependency-plugin.js +119 -1
- package/dist/plugins/circular-dependency/index.js +15 -1
- package/dist/plugins/clean-webpack/clean-webpack-plugin.js +173 -1
- package/dist/plugins/clean-webpack/index.js +22 -1
- package/dist/plugins/define-variable/define-variable-plugin.js +28 -1
- package/dist/plugins/define-variable/index.js +1 -1
- package/dist/plugins/html-inject-scripts/plugin-html-inject-script.js +27 -1
- package/dist/plugins/module-federation/external-template-remotes.js +92 -1
- package/dist/plugins/module-federation/index.js +1 -1
- package/dist/plugins/module-federation/module-federation.js +98 -1
- package/dist/plugins/multi-html/index.js +15 -1
- package/dist/plugins/multi-html/multi-html-cdn-plugin.js +84 -1
- package/dist/plugins/multi-html/multi-html-plugin.js +70 -1
- package/dist/plugins/ts-checker/index.d.ts +1 -0
- package/dist/plugins/ts-checker/index.js +1 -0
- package/dist/plugins/ts-checker/ts-checker-plugin.d.ts +4 -0
- package/dist/plugins/ts-checker/ts-checker-plugin.js +18 -0
- package/dist/types/index.js +8 -1
- package/dist/types/types-ci.js +1 -1
- package/dist/types/types-dev-server.js +1 -1
- package/dist/types/types-entry-map.js +1 -1
- package/dist/types/types-federation.js +1 -1
- package/dist/types/types-loader-options.js +1 -1
- package/dist/types/types-modular-import.js +1 -1
- package/dist/types/types-multi-html.js +1 -1
- package/dist/types/types-options.js +1 -1
- package/dist/types/types-plugin-options.js +1 -1
- package/dist/types/types-webpack.js +1 -1
- package/package.json +2 -2
@@ -1 +1,10 @@
|
|
1
|
-
import{ICON_PATH_REGEX}from
|
1
|
+
import { ICON_PATH_REGEX } from './constants.js';
|
2
|
+
/**
|
3
|
+
* Causeof we expose a component <Icon /> from `@wove/react` it can be optimized via icon-loader.
|
4
|
+
* limitation assets match `svg-icons/**\/*.svg` to icon loader resolver.
|
5
|
+
* @param resource
|
6
|
+
* @returns
|
7
|
+
*/
|
8
|
+
export const isIconSvg = (resource) => {
|
9
|
+
return ICON_PATH_REGEX.test(resource) && resource.endsWith('.svg');
|
10
|
+
};
|
@@ -1 +1 @@
|
|
1
|
-
export{};
|
1
|
+
export {};
|
package/dist/default-options.js
CHANGED
@@ -1 +1,84 @@
|
|
1
|
-
export const defaultEvolveOptions=
|
1
|
+
export const defaultEvolveOptions = {
|
2
|
+
projectCwd: process.cwd(),
|
3
|
+
projectVirtualPath: 'flatjs/evolve',
|
4
|
+
rejectWarnings: false,
|
5
|
+
devServer: {
|
6
|
+
autoOpen: true,
|
7
|
+
pageProxy: '/pages',
|
8
|
+
mockOptions: {
|
9
|
+
mockBaseDir: 'mocks',
|
10
|
+
},
|
11
|
+
clientOverlay: {
|
12
|
+
errors: true,
|
13
|
+
warnings: false,
|
14
|
+
},
|
15
|
+
webSocketURL: 'localIp',
|
16
|
+
middlewares: [],
|
17
|
+
watchOptions: {
|
18
|
+
poll: 1000,
|
19
|
+
// Use array here, easy can add a new ignore dynamic at runtime.
|
20
|
+
ignored: ['**/node_modules', '**/mocks'],
|
21
|
+
aggregateTimeout: 500,
|
22
|
+
},
|
23
|
+
defaultServeGlobalData: () => Promise.resolve({}),
|
24
|
+
bundleDirResolver: (dir) => dir,
|
25
|
+
},
|
26
|
+
webpack: {
|
27
|
+
// The default is es5
|
28
|
+
target: ['web', 'es5'],
|
29
|
+
plugins: [],
|
30
|
+
ruleSets: [],
|
31
|
+
publicPath: 'auto',
|
32
|
+
resolve: {},
|
33
|
+
externals: {
|
34
|
+
vue: 'Vue',
|
35
|
+
react: 'React',
|
36
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
37
|
+
'react-dom': 'ReactDOM',
|
38
|
+
},
|
39
|
+
outputDir: 'public',
|
40
|
+
enableBundleHashName: true,
|
41
|
+
},
|
42
|
+
pluginOptions: {},
|
43
|
+
loaderOptions: {
|
44
|
+
assetDataUrlMaxSize: 4 * 1024,
|
45
|
+
babelOptions: {
|
46
|
+
// 默认值的必须使用object类型, 如果使用函数, 会导致merge默认值失败.
|
47
|
+
usePreset: 'react',
|
48
|
+
plugins: [],
|
49
|
+
presets: [],
|
50
|
+
},
|
51
|
+
runTsChecker: true,
|
52
|
+
lessOptions: {},
|
53
|
+
postcssOptions: {
|
54
|
+
cssnanoOptions: {},
|
55
|
+
},
|
56
|
+
pixelOptions: {
|
57
|
+
rootValue: { px: 100, rpx: 1 },
|
58
|
+
outputUnit: 'rem',
|
59
|
+
},
|
60
|
+
// Always defined in evolve.config.js
|
61
|
+
modularImports: [],
|
62
|
+
},
|
63
|
+
entryMap: {},
|
64
|
+
// The configurations for plugin `@flatjs/evolve`, `multi-cdn-plugin`
|
65
|
+
multiHtmlCdn: {},
|
66
|
+
// Do not use arrow function here.
|
67
|
+
multiHtmlCdnEnvResolver: function cdnResolver() {
|
68
|
+
return undefined;
|
69
|
+
},
|
70
|
+
needVerifyPackages: {},
|
71
|
+
packageInstallChecker: {
|
72
|
+
enabled: false,
|
73
|
+
detectModules: ['@dimjs/*'],
|
74
|
+
throwError: false,
|
75
|
+
showAllInstalledGraph: true,
|
76
|
+
},
|
77
|
+
maxProcesses: 5,
|
78
|
+
/**
|
79
|
+
* CI default configurations.
|
80
|
+
*/
|
81
|
+
ci: {
|
82
|
+
basedBranch: 'origin/master',
|
83
|
+
},
|
84
|
+
};
|
@@ -1 +1,4 @@
|
|
1
|
-
import{defineConfig as myDefineConfig}from
|
1
|
+
import { defineConfig as myDefineConfig, } from '@armit/config-loader';
|
2
|
+
export const defineConfig = (userConfig) => {
|
3
|
+
return myDefineConfig(userConfig);
|
4
|
+
};
|
@@ -1 +1 @@
|
|
1
|
-
export*from
|
1
|
+
export * from './define-config.js';
|
@@ -1 +1,58 @@
|
|
1
|
-
import
|
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 enabledHmr Value indicates if we need to liveReload or `HMR`
|
7
|
+
* @param devPort The port number of `@flatjs/mock`
|
8
|
+
* @param publicIp The public ip address of local server
|
9
|
+
* @param evolveOptions The configuration of `@flatjs/evolve` (FlatEvolveOptions)
|
10
|
+
*/
|
11
|
+
export const addCompilerToDevServer = (compiler, enabledHmr, devPort, publicIp, evolveOptions) => {
|
12
|
+
const { projectCwd, devServer } = evolveOptions;
|
13
|
+
const server = new WebpackDevServer({
|
14
|
+
server: {
|
15
|
+
type: devServer?.https ? 'https' : 'http',
|
16
|
+
options: {
|
17
|
+
// Load https
|
18
|
+
...devServer?.https,
|
19
|
+
},
|
20
|
+
},
|
21
|
+
open: false,
|
22
|
+
compress: true,
|
23
|
+
port: devPort,
|
24
|
+
hot: enabledHmr,
|
25
|
+
liveReload: !enabledHmr,
|
26
|
+
// Enable firewall or set hosts that are allowed to access the dev server.
|
27
|
+
allowedHosts: 'all',
|
28
|
+
static: {
|
29
|
+
directory: `${join(projectCwd, '/public')}`,
|
30
|
+
},
|
31
|
+
headers: {
|
32
|
+
// eslint-disable-next-line @typescript-eslint/naming-convention
|
33
|
+
'Access-Control-Allow-Origin': '*',
|
34
|
+
},
|
35
|
+
client: {
|
36
|
+
progress: true,
|
37
|
+
overlay: devServer?.clientOverlay,
|
38
|
+
webSocketURL: devServer?.webSocketURL === 'localIp'
|
39
|
+
? {
|
40
|
+
hostname: publicIp || undefined,
|
41
|
+
}
|
42
|
+
: {
|
43
|
+
// always use public ip address cause of charles proxy to mobile devices don't work on `ws://${domain host}:port`
|
44
|
+
// if we use https, we don't need to specify the hostname or specify the https domain address
|
45
|
+
hostname: '0.0.0.0',
|
46
|
+
...devServer?.webSocketURL,
|
47
|
+
},
|
48
|
+
},
|
49
|
+
}, compiler);
|
50
|
+
return new Promise((resolve, reject) => {
|
51
|
+
server.startCallback((err) => {
|
52
|
+
if (err) {
|
53
|
+
return reject(err);
|
54
|
+
}
|
55
|
+
resolve(true);
|
56
|
+
});
|
57
|
+
});
|
58
|
+
};
|
@@ -1 +1,13 @@
|
|
1
|
-
import{normalizePageProxy}from
|
1
|
+
import { normalizePageProxy } from '../helpers/normalize-page-proxy.js';
|
2
|
+
import { createPageMiddleware, createPublicAssetsMiddleware, } from './middlewares/index.js';
|
3
|
+
/**
|
4
|
+
* Add route `/pages`, `*` to main web-server
|
5
|
+
*/
|
6
|
+
export const createAppPageRoute = (projectCwd, app, devHostUri, servedDevServerEntries, evolveOptions) => {
|
7
|
+
const { devServer } = evolveOptions;
|
8
|
+
const pageProxy = normalizePageProxy(devServer?.pageProxy || '/pages');
|
9
|
+
// Attach request handlers for context `/page/*`
|
10
|
+
app.use(pageProxy, ...createPageMiddleware(devHostUri, devServer?.mockOptions?.apiContext || 'api', servedDevServerEntries, evolveOptions));
|
11
|
+
// handle all no-matched page request.
|
12
|
+
app.use('*', createPublicAssetsMiddleware(projectCwd, pageProxy));
|
13
|
+
};
|
@@ -1 +1,52 @@
|
|
1
|
-
import
|
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, publicIp, 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 moduleFederationRemotes = moduleFederation?.remotes || [];
|
14
|
+
moduleFederationRemotes.forEach((remote) => {
|
15
|
+
// Dynamic construct remote endpoint as hostUri
|
16
|
+
remote.endpoint = (shortName) => {
|
17
|
+
const servedDevServerEntry = servedDevServerEntries[shortName];
|
18
|
+
if (!servedDevServerEntry) {
|
19
|
+
throw new Error(`No servedDevServerEntry found via "${shortName}"`);
|
20
|
+
}
|
21
|
+
return urlJoin(servedDevServerEntry?.devServerHostUri, ['/public']);
|
22
|
+
};
|
23
|
+
});
|
24
|
+
const { devServerPort, devServerHostUri } = servedDevServerEntries[entryName];
|
25
|
+
const singleEvolveEntryMap = {
|
26
|
+
// e.g. `home`
|
27
|
+
[entryName]: itemEntryConfig,
|
28
|
+
};
|
29
|
+
// e.g. `http://dev.flatjs.com:3002/public/`
|
30
|
+
const servePublicPath = urlJoin(devServerHostUri, ['public']);
|
31
|
+
const webpackConfig = await loadWebpackConfig('development', singleEvolveEntryMap, mergeOptions(evolveOptions, {
|
32
|
+
webpack: {
|
33
|
+
publicPath: servePublicPath,
|
34
|
+
},
|
35
|
+
}));
|
36
|
+
const enabledHmr = shouldEnableReactFastRefresh(true, [entryName, itemEntryConfig], evolveOptions);
|
37
|
+
const compiler = webpack(splitToMultiCompilerConfigs(singleEvolveEntryMap, webpackConfig, evolveOptions, enabledHmr)[0]);
|
38
|
+
// '@pmmmwh/react-refresh-webpack-plugin/client/ReactRefreshEntry.js',
|
39
|
+
serveTaks.push(
|
40
|
+
// create webpack dev server instance.
|
41
|
+
addCompilerToDevServer(compiler, enabledHmr, devServerPort, publicIp, evolveOptions));
|
42
|
+
const title = compiler.name || '';
|
43
|
+
compiler.hooks.invalid.tap('fileChange', (fileName) => {
|
44
|
+
const relativeFileName = relative(projectCwd, fileName || '');
|
45
|
+
logger.info(`file change ➩ ${chalk(['cyan'])(relativeFileName)}`, title);
|
46
|
+
});
|
47
|
+
compiler.hooks.done.tap('compileDone', () => {
|
48
|
+
logger.info(`debug page ➩ ${chalk(['cyan'])(mainPage)}`, title);
|
49
|
+
});
|
50
|
+
}
|
51
|
+
return serveTaks;
|
52
|
+
};
|
@@ -1 +1,27 @@
|
|
1
|
-
import{mergeOptions}from
|
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,24 @@
|
|
1
|
-
import https from
|
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, publicIp } = 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
|
+
publicIp,
|
19
|
+
devHostUri: hostUri,
|
20
|
+
devPort: mockPort,
|
21
|
+
});
|
22
|
+
});
|
23
|
+
});
|
24
|
+
};
|
package/dist/dev-server/index.js
CHANGED
@@ -1 +1,6 @@
|
|
1
|
-
export*from
|
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,33 @@
|
|
1
|
-
import{getPageMainHtml}from
|
1
|
+
import { getPageMainHtml } from './get-page-main-html.js';
|
2
|
+
import { getPageModuleHtml } from './get-page-module-html.js';
|
3
|
+
import { getRuntimeManifest } from './get-runtime-manifest.js';
|
4
|
+
/**
|
5
|
+
* A middleware to proxy the page modules template.
|
6
|
+
* @example `http://dev.flatjs.com:3001/pages`
|
7
|
+
* @param mode The mode of this dev server instance.
|
8
|
+
* @param hostUri The main host base url.
|
9
|
+
* @param apiContext apiBase e.g. `api`
|
10
|
+
* @param servedDevServerEntries The served webpack entries
|
11
|
+
* @param forPageMiddlewares Allow us provider customized middlewares for `page`, `modules`
|
12
|
+
* @param evolveOptions The evolve config options
|
13
|
+
*/
|
14
|
+
export const createPageMiddleware = (devHostUri, apiContext, servedDevServerEntries, evolveOptions) => {
|
15
|
+
const handler = async (req, res) => {
|
16
|
+
let html;
|
17
|
+
// Expose a special runtime manifest.json for other system to intergration
|
18
|
+
if (req.path === '/runtime/manifest.json') {
|
19
|
+
const jsonManifest = await getRuntimeManifest(servedDevServerEntries, devHostUri, evolveOptions);
|
20
|
+
return res.json(jsonManifest);
|
21
|
+
}
|
22
|
+
// For root main page
|
23
|
+
if (req.path === '/') {
|
24
|
+
html = await getPageMainHtml(servedDevServerEntries, devHostUri, evolveOptions);
|
25
|
+
}
|
26
|
+
else {
|
27
|
+
// For serve page modules
|
28
|
+
html = await getPageModuleHtml(servedDevServerEntries, req, devHostUri, apiContext, evolveOptions);
|
29
|
+
}
|
30
|
+
res.send(html);
|
31
|
+
};
|
32
|
+
return (evolveOptions.devServer?.middlewares || []).concat(handler);
|
33
|
+
};
|
@@ -1 +1,25 @@
|
|
1
|
-
import{extname,join}from
|
1
|
+
import { extname, join } from 'node:path';
|
2
|
+
import { fileWalk } from '@armit/file-utility';
|
3
|
+
export const createPublicAssetsMiddleware = (projectCwd, pageProxy) => 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(pageProxy);
|
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,24 @@
|
|
1
|
-
import{getDevServerHostUri}from
|
1
|
+
import { getDevServerHostUri } from './get-dev-server-host-uri.js';
|
2
|
+
import { getNormalizedEntryName } from './get-normalized-entry-name.js';
|
3
|
+
import { getProjectVirtualPath } from './get-project-virtual-path.js';
|
4
|
+
export function getSortedModules(evolveOptions, servedDevServerEntries, devHostUri) {
|
5
|
+
const sortedModules = [];
|
6
|
+
const projectVirtualPath = getProjectVirtualPath(evolveOptions);
|
7
|
+
for (const [entryName, entryContent] of Object.entries(evolveOptions.entryMap)) {
|
8
|
+
// `home`, servedDevServerEntries[key] => `home`
|
9
|
+
const isServedEntry = Object.keys(servedDevServerEntries).includes(entryName);
|
10
|
+
const devServerHostUri = getDevServerHostUri(servedDevServerEntries, entryName, devHostUri);
|
11
|
+
// `flatjs/evolve/home`
|
12
|
+
const normalizedEntryName = getNormalizedEntryName(entryName, projectVirtualPath, servedDevServerEntries, evolveOptions.devServer);
|
13
|
+
sortedModules.push({
|
14
|
+
entryName,
|
15
|
+
entryContent,
|
16
|
+
devHostUri,
|
17
|
+
devServerHostUri,
|
18
|
+
normalizedEntryName,
|
19
|
+
projectVirtualPath,
|
20
|
+
isServedEntry,
|
21
|
+
});
|
22
|
+
}
|
23
|
+
return sortedModules;
|
24
|
+
}
|
@@ -1 +1,7 @@
|
|
1
|
-
import{join}from
|
1
|
+
import { join } from 'node:path/posix';
|
2
|
+
import { urlJoin } from '@flatjs/common';
|
3
|
+
export const getBundleAsset = (devServerHostUri, normalizedCurrEntry, extension) => {
|
4
|
+
return urlJoin(devServerHostUri, [
|
5
|
+
join('public', normalizedCurrEntry, `bundle${extension}`),
|
6
|
+
]);
|
7
|
+
};
|
@@ -1 +1,5 @@
|
|
1
|
-
export function getDevServerHostUri(
|
1
|
+
export function getDevServerHostUri(servedDevServerEntries, currEntry, devHostUri) {
|
2
|
+
const currDevServerEntry = servedDevServerEntries[currEntry];
|
3
|
+
// Maybe No currEntry found in servedDevServerEntries, use default `hostUri`, e.g. `static` mode.
|
4
|
+
return currDevServerEntry?.devServerHostUri || devHostUri;
|
5
|
+
}
|
@@ -1 +1,14 @@
|
|
1
|
-
import{join}from
|
1
|
+
import { join } from 'node:path';
|
2
|
+
import { devReactFastRefresh } from '../../constants.js';
|
3
|
+
import { shouldEnableReactFastRefresh } from '../../helpers/should-enable-react-fast-refresh.js';
|
4
|
+
import { getBundleAsset } from './get-bundle-asset.js';
|
5
|
+
export function getHmrRuntimeChunks(servedDevServerEntries, entryName, normalizedCurrEntry, currEntryItem, evolveOptions, devServerHostUri) {
|
6
|
+
const enabledHmr = servedDevServerEntries[entryName] &&
|
7
|
+
shouldEnableReactFastRefresh(true, [normalizedCurrEntry, currEntryItem], evolveOptions);
|
8
|
+
if (enabledHmr) {
|
9
|
+
const runtimeAsset = getBundleAsset(devServerHostUri, join(normalizedCurrEntry, devReactFastRefresh.runtime), '.js');
|
10
|
+
const reactRefreshSetup = getBundleAsset(devServerHostUri, join(normalizedCurrEntry, devReactFastRefresh.reactRefreshSetup), '.js');
|
11
|
+
return [runtimeAsset, reactRefreshSetup];
|
12
|
+
}
|
13
|
+
return [];
|
14
|
+
}
|
@@ -1 +1,14 @@
|
|
1
|
-
import{normalizeEvolveEntryName}from
|
1
|
+
import { normalizeEvolveEntryName } from '../../helpers/normalize-entry-map.js';
|
2
|
+
export function getNormalizedEntryName(entryName, projectVirtualPath, servedDevServerEntries, devServer) {
|
3
|
+
let normalizedEntryName = normalizeEvolveEntryName(entryName, projectVirtualPath);
|
4
|
+
// Check if we have customized dir resolver
|
5
|
+
if (devServer?.bundleDirResolver) {
|
6
|
+
const isServedEntry = Object.keys(servedDevServerEntries).includes(entryName);
|
7
|
+
normalizedEntryName = devServer?.bundleDirResolver(normalizedEntryName, {
|
8
|
+
currEntry: entryName,
|
9
|
+
projectVirtualPath,
|
10
|
+
isServedModule: isServedEntry,
|
11
|
+
});
|
12
|
+
}
|
13
|
+
return normalizedEntryName;
|
14
|
+
}
|
@@ -1 +1,42 @@
|
|
1
|
-
import{readFileSync}from
|
1
|
+
import { readFileSync } from 'node:fs';
|
2
|
+
import { join } from 'node:path';
|
3
|
+
import { urlJoin } from '@flatjs/common';
|
4
|
+
import _ from 'lodash';
|
5
|
+
import { getPackageDir } from '../../helpers/get-pacakge-dir.js';
|
6
|
+
import { normalizePageProxy } from '../../helpers/normalize-page-proxy.js';
|
7
|
+
import { getSortedModules, } from './get-all-sorted-modules.js';
|
8
|
+
export const getPageMainHtml = async (servedDevServerEntries, devHostUri, evolveOptions) => {
|
9
|
+
const evolveCwd = getPackageDir();
|
10
|
+
const templateStr = readFileSync(join(evolveCwd, './templates/main.html'), 'utf-8');
|
11
|
+
const sortedModules = getSortedModules(evolveOptions, servedDevServerEntries, devHostUri);
|
12
|
+
const pageProxy = normalizePageProxy(evolveOptions.devServer?.pageProxy || '/pages');
|
13
|
+
const templateModules = sortedModules.map((module) => {
|
14
|
+
const { entryName, entryContent, isServedEntry, projectVirtualPath, normalizedEntryName, } = module;
|
15
|
+
const linkHref = urlJoin(devHostUri, [pageProxy, normalizedEntryName], {
|
16
|
+
env: 'me',
|
17
|
+
});
|
18
|
+
// Allow customized page main link.
|
19
|
+
const servePageMainLinkFn = entryContent.options?.servePageMainLinkFn || ((link) => link);
|
20
|
+
const link = servePageMainLinkFn(linkHref, {
|
21
|
+
hostUri: devHostUri,
|
22
|
+
entryName,
|
23
|
+
virtualPath: projectVirtualPath,
|
24
|
+
});
|
25
|
+
const displayName = entryName
|
26
|
+
.replace(projectVirtualPath, '')
|
27
|
+
.replace(/^\//, '');
|
28
|
+
return {
|
29
|
+
link,
|
30
|
+
name: displayName,
|
31
|
+
flagText: isServedEntry ? 'serve' : 'static',
|
32
|
+
isServed: isServedEntry ? 1 : 0,
|
33
|
+
};
|
34
|
+
});
|
35
|
+
const templateData = {
|
36
|
+
title: '@flatjs/evolve',
|
37
|
+
modules: templateModules.sort((a, b) => {
|
38
|
+
return b.isServed - a.isServed;
|
39
|
+
}),
|
40
|
+
};
|
41
|
+
return _.template(templateStr)(templateData);
|
42
|
+
};
|
@@ -1 +1,120 @@
|
|
1
|
-
import
|
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 { normalizePageProxy } from '../../helpers/normalize-page-proxy.js';
|
10
|
+
import { injectFederationScripts } from '../../helpers/script-injects.js';
|
11
|
+
import { getBundleAsset } from './get-bundle-asset.js';
|
12
|
+
import { getDevServerHostUri } from './get-dev-server-host-uri.js';
|
13
|
+
import { getHmrRuntimeChunks } from './get-hmr-runtime-chunks.js';
|
14
|
+
import { getNormalizedEntryName } from './get-normalized-entry-name.js';
|
15
|
+
export const getPageModuleHtml = async (servedDevServerEntries, req, devHostUri, apiContext, evolveOptions
|
16
|
+
// eslint-disable-next-line sonarjs/cognitive-complexity
|
17
|
+
) => {
|
18
|
+
const { entryMap, projectVirtualPath } = evolveOptions;
|
19
|
+
// normalize to ['a/b','a/b/c','inn/app/transfer_list','inn/app/transfer']
|
20
|
+
const entryNames = Object.keys(entryMap).sort((a, b) => b.length - a.length);
|
21
|
+
const evolveCwd = getPackageDir();
|
22
|
+
const currEntryName = entryNames.find((entryName) => {
|
23
|
+
const normalizedEntryName = normalizeEvolveEntryName(entryName, projectVirtualPath);
|
24
|
+
return ensureSlash(req.path.replace(/^\//, ''), true).startsWith(ensureSlash(normalizedEntryName, true));
|
25
|
+
});
|
26
|
+
if (!currEntryName) {
|
27
|
+
const notFoundTemplateStr = readFileSync(join(evolveCwd, `./templates/module-404.html`), 'utf-8');
|
28
|
+
return _.template(notFoundTemplateStr)({
|
29
|
+
title: '404 Not Found',
|
30
|
+
errorMeta: [
|
31
|
+
{
|
32
|
+
name: `@flatjs/evolve workspace`,
|
33
|
+
value: evolveCwd,
|
34
|
+
},
|
35
|
+
{
|
36
|
+
name: `served entry names`,
|
37
|
+
value: JSON.stringify(entryNames),
|
38
|
+
},
|
39
|
+
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
40
|
+
{ name: `module path`, value: `${req.path}` },
|
41
|
+
],
|
42
|
+
});
|
43
|
+
}
|
44
|
+
const currEntryItem = entryMap[currEntryName];
|
45
|
+
const currEntryOption = currEntryItem.options;
|
46
|
+
// currEntry: `home`
|
47
|
+
const devServerHostUri = getDevServerHostUri(servedDevServerEntries, currEntryName, devHostUri);
|
48
|
+
const moduleTemplate =
|
49
|
+
// eslint-disable-next-line sonarjs/no-duplicate-string
|
50
|
+
currEntryOption?.serveModuleTemplate || './templates/module.html';
|
51
|
+
const projectHostedModuleTemplate = join(evolveOptions.projectCwd, './templates/module.html');
|
52
|
+
const templateStr = readFileSync(isAbsolute(moduleTemplate)
|
53
|
+
? moduleTemplate
|
54
|
+
: existsSync(projectHostedModuleTemplate)
|
55
|
+
? projectHostedModuleTemplate
|
56
|
+
: join(evolveCwd, './templates/module.html'), 'utf-8');
|
57
|
+
const devServer = evolveOptions.devServer;
|
58
|
+
const defaultGlobalData = devServer?.defaultServeGlobalData
|
59
|
+
? await devServer.defaultServeGlobalData(currEntryItem, devHostUri)
|
60
|
+
: {};
|
61
|
+
const configData = {
|
62
|
+
mode: 'development',
|
63
|
+
// FIXME: always use `devHostUri` as served local `cdn`, if you want to serve `anther` module
|
64
|
+
// you need to generate cdn path manually.
|
65
|
+
envCdn: urlJoin(devHostUri, ['public']),
|
66
|
+
};
|
67
|
+
// Get normalized entry name
|
68
|
+
const normalizedEntryName = getNormalizedEntryName(currEntryName, projectVirtualPath, servedDevServerEntries, devServer);
|
69
|
+
const pageProxy = normalizePageProxy(devServer?.pageProxy || '/pages');
|
70
|
+
const templateData = {
|
71
|
+
// title
|
72
|
+
title: getHtmlPluginConfig('title', configData, currEntryOption?.title),
|
73
|
+
// favicon
|
74
|
+
favicon: getHtmlPluginConfig('favicon', configData, currEntryOption?.favicon),
|
75
|
+
// `allowPx2rem` default is true
|
76
|
+
viewport: allowPx2remForModule([currEntryName, currEntryItem], evolveOptions)
|
77
|
+
? getHtmlPluginConfig('viewport', configData, currEntryOption?.viewport)
|
78
|
+
: '',
|
79
|
+
// The customized html tags should be inject to <header />
|
80
|
+
headBeforeHtmlTags: getHtmlPluginConfig('headBeforeHtmlTags', configData, currEntryOption?.headBeforeHtmlTags),
|
81
|
+
// Allow us customized inline scripts into compiled html template.
|
82
|
+
inlineScripts: getHtmlPluginConfig('inlineScripts', configData, currEntryOption?.inlineScripts),
|
83
|
+
// The ordered styles will be injected start of html head.
|
84
|
+
headBeforeStyles: getHtmlPluginConfig('headBeforeStyles', configData, currEntryOption?.headBeforeStyles),
|
85
|
+
// The ordered scripts will be injected before html head.
|
86
|
+
headBeforeScripts: getHtmlPluginConfig('headBeforeScripts', configData, currEntryOption?.headBeforeScripts),
|
87
|
+
// The ordered scripts will be injected end of html body.
|
88
|
+
bodyAfterScripts: getHtmlPluginConfig('bodyAfterScripts', configData, currEntryOption?.bodyAfterScripts),
|
89
|
+
// Module Federation, Only for `static` mode, `serve` mode it will use entryItemConfig.endpoint()
|
90
|
+
moduleFederationScripts: injectFederationScripts({
|
91
|
+
me: [urlJoin(devHostUri, ['public'])],
|
92
|
+
}, evolveOptions.multiHtmlCdnEnvResolver),
|
93
|
+
// The global data.
|
94
|
+
global: {
|
95
|
+
hostUrl: devHostUri,
|
96
|
+
apiBase: urlJoin(devHostUri, [apiContext]),
|
97
|
+
virtualPath: join(pageProxy, projectVirtualPath),
|
98
|
+
moduleName: currEntryName
|
99
|
+
.replace(projectVirtualPath, '')
|
100
|
+
.replace(/^\//, ''),
|
101
|
+
...defaultGlobalData,
|
102
|
+
...(currEntryOption?.serveGlobalData || {}),
|
103
|
+
},
|
104
|
+
styles: [getBundleAsset(devServerHostUri, normalizedEntryName, '.css')],
|
105
|
+
scripts: [getBundleAsset(devServerHostUri, normalizedEntryName, '.js')],
|
106
|
+
};
|
107
|
+
if (!templateData.headBeforeHtmlTags) {
|
108
|
+
templateData.headBeforeHtmlTags = [];
|
109
|
+
}
|
110
|
+
else {
|
111
|
+
// Avoid deep object reference here.
|
112
|
+
templateData.headBeforeHtmlTags = templateData.headBeforeHtmlTags.slice(0);
|
113
|
+
}
|
114
|
+
// Indicates current we use `hot` mode for `webpack-dev-server` hot reload true.
|
115
|
+
const devRuntimeChunks = getHmrRuntimeChunks(servedDevServerEntries, currEntryName, normalizedEntryName, currEntryItem, evolveOptions, devServerHostUri);
|
116
|
+
devRuntimeChunks.forEach((runtimeChunk) => {
|
117
|
+
templateData.headBeforeHtmlTags?.push(`<script src="${runtimeChunk}"></script>`);
|
118
|
+
});
|
119
|
+
return _.template(templateStr)(templateData);
|
120
|
+
};
|