@umijs/preset-umi 4.0.0-beta.12 → 4.0.0-beta.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/build.js +1 -1
- package/dist/commands/dev/createRouteMiddleware.js +7 -3
- package/dist/commands/dev/dev.js +6 -1
- package/dist/commands/dev/getMarkupArgs.d.ts +2 -0
- package/dist/commands/dev/getMarkupArgs.js +3 -0
- package/dist/features/appData/appData.js +33 -0
- package/dist/features/check/check.js +11 -0
- package/dist/features/configPlugins/configPlugins.js +7 -3
- package/dist/features/configPlugins/schema.js +12 -4
- package/dist/features/esmi/Service.d.ts +19 -0
- package/dist/features/esmi/Service.js +72 -3
- package/dist/features/esmi/esbuildPlugins/requireToImport.d.ts +8 -0
- package/dist/features/esmi/esbuildPlugins/requireToImport.js +61 -0
- package/dist/features/esmi/esbuildPlugins/topLevelExternal.d.ts +13 -0
- package/dist/features/esmi/esbuildPlugins/topLevelExternal.js +37 -0
- package/dist/features/esmi/esmi.js +81 -12
- package/dist/features/favicon/favicon.js +3 -1
- package/dist/features/lowImport/babelPlugin.d.ts +2 -0
- package/dist/features/lowImport/babelPlugin.js +28 -6
- package/dist/features/lowImport/lowImport.js +8 -3
- package/dist/features/mock/getMockData.d.ts +4 -0
- package/dist/features/mock/getMockData.js +10 -5
- package/dist/features/mock/mock.js +9 -2
- package/dist/features/polyfill/polyfill.js +38 -8
- package/dist/features/polyfill/publicPathPolyfill.d.ts +3 -0
- package/dist/features/polyfill/publicPathPolyfill.js +14 -0
- package/dist/features/tmpFiles/routes.js +14 -2
- package/dist/features/tmpFiles/tmpFiles.js +93 -8
- package/dist/index.js +2 -0
- package/dist/libs/scan.d.ts +5 -1
- package/dist/libs/scan.js +41 -1
- package/dist/registerMethods.js +6 -1
- package/dist/types.d.ts +2 -1
- package/dist/utils/transformIEAR.d.ts +22 -0
- package/dist/utils/transformIEAR.js +100 -0
- package/package.json +16 -15
- package/templates/history.tpl +15 -0
- package/templates/plugin.tpl +14 -0
- package/templates/umi.tpl +32 -7
- package/dist/libs/moduleGraph.d.ts +0 -2
- package/dist/libs/moduleGraph.js +0 -6
package/dist/commands/build.js
CHANGED
|
@@ -110,7 +110,7 @@ umi build --clean
|
|
|
110
110
|
const { vite } = api.args;
|
|
111
111
|
const markupArgs = yield (0, getMarkupArgs_1.getMarkupArgs)({ api });
|
|
112
112
|
// @ts-ignore
|
|
113
|
-
const markup = yield (0, server_1.getMarkup)(Object.assign(Object.assign({}, markupArgs), { scripts: ['/umi.js'].concat(markupArgs.scripts), esmScript: !!opts.config.esm || vite, path: '/' }));
|
|
113
|
+
const markup = yield (0, server_1.getMarkup)(Object.assign(Object.assign({}, markupArgs), { styles: ['/umi.css'].concat(markupArgs.styles), scripts: ['/umi.js'].concat(markupArgs.scripts), esmScript: !!opts.config.esm || vite, path: '/' }));
|
|
114
114
|
(0, fs_1.writeFileSync)((0, path_1.join)(api.paths.absOutputPath, 'index.html'), markup, 'utf-8');
|
|
115
115
|
utils_1.logger.event('build index.html');
|
|
116
116
|
// print size
|
|
@@ -24,11 +24,15 @@ window.__vite_plugin_react_preamble_installed__ = true
|
|
|
24
24
|
function createRouteMiddleware(opts) {
|
|
25
25
|
return (req, res, next) => __awaiter(this, void 0, void 0, function* () {
|
|
26
26
|
const { vite } = opts.api.args;
|
|
27
|
+
const viteScripts = [
|
|
28
|
+
// add noshim attr for skip importmap shim logic for this modules
|
|
29
|
+
{ content: viteRefreshScript, noshim: '' },
|
|
30
|
+
{ src: '/@vite/client', noshim: '' },
|
|
31
|
+
opts.api.appData.hasSrcDir ? '/src/.umi/umi.ts' : '/.umi/umi.ts',
|
|
32
|
+
];
|
|
27
33
|
const markupArgs = yield (0, getMarkupArgs_1.getMarkupArgs)(opts);
|
|
28
34
|
// @ts-ignore
|
|
29
|
-
const requestHandler = yield (0, server_1.createRequestHandler)(Object.assign(Object.assign({}, markupArgs), { scripts: (vite
|
|
30
|
-
? [viteRefreshScript, '/@vite/client', '/.umi/umi.ts']
|
|
31
|
-
: ['/umi.js']).concat(markupArgs.scripts), esmScript: vite }));
|
|
35
|
+
const requestHandler = yield (0, server_1.createRequestHandler)(Object.assign(Object.assign({}, markupArgs), { styles: ['/umi.css'].concat(markupArgs.styles), scripts: (vite ? viteScripts : ['/umi.js']).concat(markupArgs.scripts), esmScript: vite }));
|
|
32
36
|
requestHandler(req, res, next);
|
|
33
37
|
});
|
|
34
38
|
}
|
package/dist/commands/dev/dev.js
CHANGED
|
@@ -238,7 +238,12 @@ PORT=8888 umi dev
|
|
|
238
238
|
key: 'onDevCompileDone',
|
|
239
239
|
args: opts,
|
|
240
240
|
});
|
|
241
|
-
}, mfsuWithESBuild: (_a = api.config.mfsu) === null || _a === void 0 ? void 0 : _a.esbuild
|
|
241
|
+
}, mfsuWithESBuild: (_a = api.config.mfsu) === null || _a === void 0 ? void 0 : _a.esbuild, cache: {
|
|
242
|
+
buildDependencies: [
|
|
243
|
+
api.pkgPath,
|
|
244
|
+
api.service.configManager.mainConfigFile || '',
|
|
245
|
+
].filter(Boolean),
|
|
246
|
+
} });
|
|
242
247
|
if (enableVite) {
|
|
243
248
|
yield bundlerVite.dev(opts);
|
|
244
249
|
}
|
|
@@ -15,6 +15,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
15
15
|
exports.getMarkupArgs = void 0;
|
|
16
16
|
const cheerio_1 = __importDefault(require("@umijs/utils/compiled/cheerio"));
|
|
17
17
|
function getMarkupArgs(opts) {
|
|
18
|
+
var _a;
|
|
18
19
|
return __awaiter(this, void 0, void 0, function* () {
|
|
19
20
|
const headScripts = yield opts.api.applyPlugins({
|
|
20
21
|
key: 'addHTMLHeadScripts',
|
|
@@ -41,6 +42,8 @@ function getMarkupArgs(opts) {
|
|
|
41
42
|
initialValue: opts.api.config.favicon,
|
|
42
43
|
});
|
|
43
44
|
return {
|
|
45
|
+
mountElementId: opts.api.config.mountElementId,
|
|
46
|
+
base: ((_a = opts.api.config.history) === null || _a === void 0 ? void 0 : _a.type) === 'browser' ? opts.api.config.base : '/',
|
|
44
47
|
routes: opts.api.appData.routes,
|
|
45
48
|
favicon,
|
|
46
49
|
headScripts,
|
|
@@ -9,8 +9,11 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const bundler_utils_1 = require("@umijs/bundler-utils");
|
|
12
13
|
const utils_1 = require("@umijs/utils");
|
|
14
|
+
const fs_1 = require("fs");
|
|
13
15
|
const path_1 = require("path");
|
|
16
|
+
const watch_1 = require("../../commands/dev/watch");
|
|
14
17
|
const routes_1 = require("../tmpFiles/routes");
|
|
15
18
|
exports.default = (api) => {
|
|
16
19
|
api.modifyAppData((memo) => __awaiter(void 0, void 0, void 0, function* () {
|
|
@@ -25,6 +28,36 @@ exports.default = (api) => {
|
|
|
25
28
|
memo.react = {
|
|
26
29
|
version: require((0, path_1.join)(api.config.alias.react, 'package.json')).version,
|
|
27
30
|
};
|
|
31
|
+
memo.appJS = yield getAppJsInfo();
|
|
28
32
|
return memo;
|
|
29
33
|
}));
|
|
34
|
+
// Execute earliest, so that other onGenerateFiles can get it
|
|
35
|
+
api.register({
|
|
36
|
+
key: 'onGenerateFiles',
|
|
37
|
+
fn(args) {
|
|
38
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
if (!args.isFirstTime) {
|
|
40
|
+
api.appData.appJS = yield getAppJsInfo();
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
},
|
|
44
|
+
stage: Number.NEGATIVE_INFINITY,
|
|
45
|
+
});
|
|
46
|
+
function getAppJsInfo() {
|
|
47
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
48
|
+
for (const path of (0, watch_1.expandJSPaths)((0, path_1.join)(api.paths.absSrcPath, 'app'))) {
|
|
49
|
+
if ((0, fs_1.existsSync)(path)) {
|
|
50
|
+
const [_, exports] = yield (0, bundler_utils_1.parseModule)({
|
|
51
|
+
path,
|
|
52
|
+
content: (0, fs_1.readFileSync)(path, 'utf-8'),
|
|
53
|
+
});
|
|
54
|
+
return {
|
|
55
|
+
path,
|
|
56
|
+
exports,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return null;
|
|
61
|
+
});
|
|
62
|
+
}
|
|
30
63
|
};
|
|
@@ -31,4 +31,15 @@ exports.default = (api) => {
|
|
|
31
31
|
},
|
|
32
32
|
});
|
|
33
33
|
}));
|
|
34
|
+
api.onCheckCode((args) => {
|
|
35
|
+
// Fixed version import is not allowed
|
|
36
|
+
// e.g. import { X } from '_@ant-design_icons@4.7.0@ant-design/icons'
|
|
37
|
+
if (['cnpm', 'tnpm'].includes(api.appData.npmClient)) {
|
|
38
|
+
args.imports.forEach(({ source }) => {
|
|
39
|
+
if (/@\d/.test(source)) {
|
|
40
|
+
throw new Error(`${source} is not allowed to import.`);
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
});
|
|
34
45
|
};
|
|
@@ -16,8 +16,7 @@ function resolveProjectDep(opts) {
|
|
|
16
16
|
exports.default = (api) => {
|
|
17
17
|
const configDefaults = {
|
|
18
18
|
alias: {
|
|
19
|
-
umi:
|
|
20
|
-
'@umijs/renderer-react': (0, path_1.dirname)(require.resolve('@umijs/renderer-react/package.json')),
|
|
19
|
+
umi: '@@/exports',
|
|
21
20
|
react: resolveProjectDep({
|
|
22
21
|
pkg: api.pkg,
|
|
23
22
|
cwd: api.cwd,
|
|
@@ -34,6 +33,9 @@ exports.default = (api) => {
|
|
|
34
33
|
externals: {},
|
|
35
34
|
autoCSSModules: true,
|
|
36
35
|
publicPath: '/',
|
|
36
|
+
mountElementId: 'root',
|
|
37
|
+
base: '/',
|
|
38
|
+
history: { type: 'browser' },
|
|
37
39
|
};
|
|
38
40
|
const bundleSchemas = (0, schema_1.getSchemas)();
|
|
39
41
|
const extraSchemas = (0, schema_2.getSchemas)();
|
|
@@ -55,7 +57,9 @@ exports.default = (api) => {
|
|
|
55
57
|
}
|
|
56
58
|
// api.paths is ready after register
|
|
57
59
|
api.modifyConfig((memo, args) => {
|
|
58
|
-
memo.alias = Object.assign(Object.assign({}, memo.alias), { '@': args.paths.absSrcPath, '@@': args.paths.absTmpPath
|
|
60
|
+
memo.alias = Object.assign(Object.assign({}, memo.alias), { '@': args.paths.absSrcPath, '@@': args.paths.absTmpPath,
|
|
61
|
+
// like vite, use to pre-bundling dependencies in vite mode
|
|
62
|
+
'@fs': '/' });
|
|
59
63
|
return memo;
|
|
60
64
|
});
|
|
61
65
|
};
|
|
@@ -4,13 +4,21 @@ exports.getSchemas = void 0;
|
|
|
4
4
|
const utils_1 = require("@umijs/utils");
|
|
5
5
|
function getSchemas() {
|
|
6
6
|
return {
|
|
7
|
-
|
|
8
|
-
publicPath: (Joi) => Joi.string().regex(/\/$/).error(new Error('publicPath must end with /')),
|
|
7
|
+
base: (Joi) => Joi.string(),
|
|
9
8
|
favicon: (Joi) => Joi.string(),
|
|
10
|
-
headScripts: (Joi) => Joi.array()
|
|
11
|
-
|
|
9
|
+
headScripts: (Joi) => Joi.array(),
|
|
10
|
+
history: (Joi) => Joi.object({
|
|
11
|
+
type: Joi.string().valid('browser', 'hash', 'memory'),
|
|
12
|
+
}),
|
|
13
|
+
links: (Joi) => Joi.array(),
|
|
14
|
+
metas: (Joi) => Joi.array(),
|
|
15
|
+
mountElementId: (Joi) => Joi.string(),
|
|
12
16
|
npmClient: (Joi) => Joi.string().valid(utils_1.NpmClientEnum.pnpm, utils_1.NpmClientEnum.tnpm, utils_1.NpmClientEnum.cnpm, utils_1.NpmClientEnum.yarn, utils_1.NpmClientEnum.npm),
|
|
17
|
+
plugins: (Joi) => Joi.array().items(Joi.string()),
|
|
18
|
+
publicPath: (Joi) => Joi.string().regex(/\/$/).error(new Error('publicPath must end with /')),
|
|
13
19
|
routes: (Joi) => Joi.array().items(Joi.object()),
|
|
20
|
+
scripts: (Joi) => Joi.array(),
|
|
21
|
+
styles: (Joi) => Joi.array(),
|
|
14
22
|
};
|
|
15
23
|
}
|
|
16
24
|
exports.getSchemas = getSchemas;
|
|
@@ -38,9 +38,28 @@ export interface IPkgData {
|
|
|
38
38
|
*/
|
|
39
39
|
export default class ESMIService {
|
|
40
40
|
cdnOrigin: string;
|
|
41
|
+
cacheDir: string;
|
|
42
|
+
cache: Record<string, IImportmapData>;
|
|
41
43
|
constructor(opts: {
|
|
42
44
|
cdnOrigin: string;
|
|
45
|
+
cacheDir: string;
|
|
43
46
|
});
|
|
47
|
+
/**
|
|
48
|
+
* get cache file path by cache key
|
|
49
|
+
* @param data pkg data
|
|
50
|
+
*/
|
|
51
|
+
static getCacheKey(data: IPkgData): string;
|
|
52
|
+
/**
|
|
53
|
+
* get importmap cache by cache key
|
|
54
|
+
* @param key cache key
|
|
55
|
+
*/
|
|
56
|
+
getCache(key: string): IImportmapData;
|
|
57
|
+
/**
|
|
58
|
+
* set importmap cache
|
|
59
|
+
* @param key cache key
|
|
60
|
+
* @param data importmap data
|
|
61
|
+
*/
|
|
62
|
+
setCache(key: string, data: IImportmapData): void;
|
|
44
63
|
/**
|
|
45
64
|
* build importmap from deps tree
|
|
46
65
|
* @param data package data
|
|
@@ -8,15 +8,64 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
const utils_1 = require("@umijs/utils");
|
|
16
|
+
const crypto_1 = require("crypto");
|
|
17
|
+
const fs_1 = __importDefault(require("fs"));
|
|
18
|
+
const path_1 = __importDefault(require("path"));
|
|
13
19
|
/**
|
|
14
20
|
* class for connect esmi server
|
|
15
21
|
*/
|
|
16
22
|
class ESMIService {
|
|
17
23
|
constructor(opts) {
|
|
18
24
|
this.cdnOrigin = '';
|
|
25
|
+
this.cacheDir = '';
|
|
26
|
+
this.cache = {};
|
|
19
27
|
this.cdnOrigin = opts.cdnOrigin;
|
|
28
|
+
this.cacheDir = opts.cacheDir;
|
|
29
|
+
// restore local cache
|
|
30
|
+
const cacheFilePath = path_1.default.join(this.cacheDir, 'importmap.json');
|
|
31
|
+
if (fs_1.default.existsSync(cacheFilePath)) {
|
|
32
|
+
try {
|
|
33
|
+
this.cache = require(cacheFilePath);
|
|
34
|
+
}
|
|
35
|
+
catch (_a) {
|
|
36
|
+
/* nothing */
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* get cache file path by cache key
|
|
42
|
+
* @param data pkg data
|
|
43
|
+
*/
|
|
44
|
+
static getCacheKey(data) {
|
|
45
|
+
const hash = (0, crypto_1.createHash)('md4');
|
|
46
|
+
hash.update(JSON.stringify(data.pkgInfo.exports));
|
|
47
|
+
return hash.digest('hex');
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* get importmap cache by cache key
|
|
51
|
+
* @param key cache key
|
|
52
|
+
*/
|
|
53
|
+
getCache(key) {
|
|
54
|
+
return this.cache[key];
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* set importmap cache
|
|
58
|
+
* @param key cache key
|
|
59
|
+
* @param data importmap data
|
|
60
|
+
*/
|
|
61
|
+
setCache(key, data) {
|
|
62
|
+
this.cache[key] = data;
|
|
63
|
+
// create cache dir
|
|
64
|
+
if (!fs_1.default.existsSync(this.cacheDir)) {
|
|
65
|
+
fs_1.default.mkdirSync(this.cacheDir, { recursive: true });
|
|
66
|
+
}
|
|
67
|
+
// write cache to file system
|
|
68
|
+
fs_1.default.writeFileSync(path_1.default.join(this.cacheDir, 'importmap.json'), JSON.stringify(this.cache, null, 2));
|
|
20
69
|
}
|
|
21
70
|
/**
|
|
22
71
|
* build importmap from deps tree
|
|
@@ -37,16 +86,36 @@ class ESMIService {
|
|
|
37
86
|
*/
|
|
38
87
|
getImportmap(data) {
|
|
39
88
|
return __awaiter(this, void 0, void 0, function* () {
|
|
89
|
+
const cacheKey = ESMIService.getCacheKey(data);
|
|
90
|
+
const cache = this.getCache(cacheKey);
|
|
91
|
+
const stamp = +new Date();
|
|
92
|
+
// use valid cache first
|
|
93
|
+
if (cache) {
|
|
94
|
+
utils_1.logger.info('ESMi cache used');
|
|
95
|
+
return cache;
|
|
96
|
+
}
|
|
97
|
+
// log dependency list
|
|
98
|
+
utils_1.logger.info(utils_1.chalk.greenBright('Pre-compiling dependencies on esmi:'));
|
|
99
|
+
data.pkgInfo.exports[0].deps.forEach((dep) => {
|
|
100
|
+
console.log(utils_1.chalk.yellow(` ${dep.name}`));
|
|
101
|
+
});
|
|
40
102
|
// get the build ticket id
|
|
41
103
|
const ticketId = yield this.build(data);
|
|
42
|
-
|
|
104
|
+
utils_1.logger.info(`ticketId: ${ticketId}`);
|
|
105
|
+
// continue to the next request after 2s
|
|
43
106
|
const next = () => new Promise((resolve) => setTimeout(() => resolve(deferrer()), 2000));
|
|
44
107
|
const deferrer = () => {
|
|
45
108
|
return utils_1.axios
|
|
46
109
|
.get(`${this.cdnOrigin}/api/v1/esm/importmap/${ticketId}`)
|
|
47
|
-
.then((res) =>
|
|
110
|
+
.then((res) => {
|
|
111
|
+
if (res.data.success) {
|
|
112
|
+
this.setCache(cacheKey, res.data.data);
|
|
113
|
+
utils_1.logger.info(`Done, took ${((+new Date() - stamp) / 1000).toFixed(1)}s`);
|
|
114
|
+
return res.data.data;
|
|
115
|
+
}
|
|
116
|
+
return next();
|
|
117
|
+
}, next);
|
|
48
118
|
};
|
|
49
|
-
// TODO: timeout + time spend log
|
|
50
119
|
return deferrer();
|
|
51
120
|
});
|
|
52
121
|
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Plugin } from '@umijs/bundler-utils/compiled/esbuild';
|
|
2
|
+
import type { DepOptimizationOptions } from 'vite';
|
|
3
|
+
/**
|
|
4
|
+
* transform require call to import
|
|
5
|
+
*/
|
|
6
|
+
export default function requireToImportPlugin({ exclude, }: {
|
|
7
|
+
exclude: NonNullable<DepOptimizationOptions['exclude']>;
|
|
8
|
+
}): Plugin;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const lodash_1 = require("@umijs/utils/compiled/lodash");
|
|
13
|
+
/**
|
|
14
|
+
* transform require call to import
|
|
15
|
+
*/
|
|
16
|
+
function requireToImportPlugin({ exclude, }) {
|
|
17
|
+
const regSafeExclude = exclude.map((e) => e.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
18
|
+
const requireRegExp = new RegExp(`^(${regSafeExclude.join('|')})$`);
|
|
19
|
+
return {
|
|
20
|
+
name: 'preset-umi:esmi-require-to-import',
|
|
21
|
+
setup(build) {
|
|
22
|
+
// handler require calls for external deps
|
|
23
|
+
build.onResolve({
|
|
24
|
+
filter: requireRegExp,
|
|
25
|
+
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
26
|
+
if (args.kind === 'require-call') {
|
|
27
|
+
return {
|
|
28
|
+
path: args.path,
|
|
29
|
+
namespace: 'esmi-require-to-import',
|
|
30
|
+
pluginData: {
|
|
31
|
+
resolveDir: args.resolveDir,
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}));
|
|
36
|
+
// replace load content
|
|
37
|
+
build.onLoad({
|
|
38
|
+
filter: /.*/,
|
|
39
|
+
namespace: 'esmi-require-to-import',
|
|
40
|
+
}, (args) => {
|
|
41
|
+
const { resolveDir } = args.pluginData || {};
|
|
42
|
+
const packageName = args.path;
|
|
43
|
+
const starSpecifier = `${(0, lodash_1.camelCase)(packageName)}Star`;
|
|
44
|
+
const defaultSpecifier = `${(0, lodash_1.camelCase)(packageName)}Default`;
|
|
45
|
+
return {
|
|
46
|
+
resolveDir,
|
|
47
|
+
contents: [
|
|
48
|
+
`import * as ${starSpecifier} from '${packageName}';`,
|
|
49
|
+
'',
|
|
50
|
+
`const ${defaultSpecifier} = ${starSpecifier}.default ? ${starSpecifier}.default : ${starSpecifier};`,
|
|
51
|
+
'',
|
|
52
|
+
`export default ${defaultSpecifier};`,
|
|
53
|
+
`export * from '${packageName}';`,
|
|
54
|
+
'',
|
|
55
|
+
].join('\n'),
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
exports.default = requireToImportPlugin;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { Plugin } from '@umijs/bundler-utils/compiled/esbuild';
|
|
2
|
+
import type { DepOptimizationOptions } from 'vite';
|
|
3
|
+
import type { createResolver } from '../../../libs/scan';
|
|
4
|
+
/**
|
|
5
|
+
* only external top level import, exclude sub-path imports for esmi
|
|
6
|
+
* example:
|
|
7
|
+
* - import from 'antd' will be externalized
|
|
8
|
+
* - import from 'antd/dist/antd.less' will not be externalized
|
|
9
|
+
*/
|
|
10
|
+
export default function topLevelExternal({ exclude, resolver, }: {
|
|
11
|
+
exclude: NonNullable<DepOptimizationOptions['exclude']>;
|
|
12
|
+
resolver: ReturnType<typeof createResolver>;
|
|
13
|
+
}): Plugin;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
/**
|
|
13
|
+
* only external top level import, exclude sub-path imports for esmi
|
|
14
|
+
* example:
|
|
15
|
+
* - import from 'antd' will be externalized
|
|
16
|
+
* - import from 'antd/dist/antd.less' will not be externalized
|
|
17
|
+
*/
|
|
18
|
+
function topLevelExternal({ exclude, resolver, }) {
|
|
19
|
+
const regSafeExclude = exclude.map((e) => e.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
|
|
20
|
+
const subImportRegExp = new RegExp(`^(${regSafeExclude.join('|')})/`);
|
|
21
|
+
const extRegExp = /\.((?<!d)\.ts|jsx?|tsx)$/;
|
|
22
|
+
return {
|
|
23
|
+
name: 'preset-umi:esmi-top-level-external',
|
|
24
|
+
setup(build) {
|
|
25
|
+
build.onResolve({
|
|
26
|
+
filter: subImportRegExp,
|
|
27
|
+
}, (args) => __awaiter(this, void 0, void 0, function* () {
|
|
28
|
+
const resolved = yield resolver.resolve(args.resolveDir, args.path);
|
|
29
|
+
// only process javascript-like files
|
|
30
|
+
if (extRegExp.test(resolved)) {
|
|
31
|
+
return { path: resolved };
|
|
32
|
+
}
|
|
33
|
+
}));
|
|
34
|
+
},
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
exports.default = topLevelExternal;
|
|
@@ -16,8 +16,11 @@ const es_module_lexer_1 = require("@umijs/bundler-utils/compiled/es-module-lexer
|
|
|
16
16
|
const magic_string_1 = __importDefault(require("magic-string"));
|
|
17
17
|
const path_1 = require("path");
|
|
18
18
|
const scan_1 = require("../../libs/scan");
|
|
19
|
+
const requireToImport_1 = __importDefault(require("./esbuildPlugins/requireToImport"));
|
|
20
|
+
const topLevelExternal_1 = __importDefault(require("./esbuildPlugins/topLevelExternal"));
|
|
19
21
|
const Service_1 = __importDefault(require("./Service"));
|
|
20
22
|
let importmap = { imports: {}, scopes: {} };
|
|
23
|
+
let importmatches = {};
|
|
21
24
|
/**
|
|
22
25
|
* esmi vite plugin
|
|
23
26
|
*/
|
|
@@ -25,13 +28,36 @@ function esmi(opts) {
|
|
|
25
28
|
return {
|
|
26
29
|
name: 'preset-umi:esmi',
|
|
27
30
|
configResolved(config) {
|
|
31
|
+
var _a, _b;
|
|
32
|
+
var _c, _d;
|
|
28
33
|
const { include, exclude } = config.optimizeDeps;
|
|
34
|
+
(_a = (_c = config.optimizeDeps).include) !== null && _a !== void 0 ? _a : (_c.include = []);
|
|
29
35
|
// do not pre-compile deps which will be loaded by importmap (for top-level deps)
|
|
30
36
|
if (include === null || include === void 0 ? void 0 : include.length) {
|
|
31
|
-
config.optimizeDeps.include = include.filter((item) => !importmap.imports[item]);
|
|
37
|
+
config.optimizeDeps.include = include.filter((item) => !importmatches[item] && !importmap.imports[item]);
|
|
32
38
|
}
|
|
33
|
-
// exclude pre-compile deps
|
|
34
|
-
config.optimizeDeps.exclude =
|
|
39
|
+
// exclude pre-compile deps
|
|
40
|
+
config.optimizeDeps.exclude = [
|
|
41
|
+
...new Set([
|
|
42
|
+
// deps from user config
|
|
43
|
+
...(exclude || []),
|
|
44
|
+
// deps from local scan
|
|
45
|
+
...Object.keys(importmatches),
|
|
46
|
+
// deps from esmi analyze result
|
|
47
|
+
...Object.keys(importmap.imports),
|
|
48
|
+
]),
|
|
49
|
+
];
|
|
50
|
+
// apply esbuild plugins
|
|
51
|
+
(_b = (_d = config.optimizeDeps).esbuildOptions) !== null && _b !== void 0 ? _b : (_d.esbuildOptions = {});
|
|
52
|
+
config.optimizeDeps.esbuildOptions.plugins = [
|
|
53
|
+
// transform require call to import
|
|
54
|
+
(0, requireToImport_1.default)({ exclude: config.optimizeDeps.exclude }),
|
|
55
|
+
// make sure vite only external top-level npm imports, and resolve sub-path npm imports
|
|
56
|
+
(0, topLevelExternal_1.default)({
|
|
57
|
+
exclude: config.optimizeDeps.exclude,
|
|
58
|
+
resolver: opts.resolver,
|
|
59
|
+
}),
|
|
60
|
+
].concat(config.optimizeDeps.esbuildOptions.plugins || []);
|
|
35
61
|
},
|
|
36
62
|
transform(source) {
|
|
37
63
|
try {
|
|
@@ -42,9 +68,17 @@ function esmi(opts) {
|
|
|
42
68
|
imports.forEach((item) => {
|
|
43
69
|
const { n: specifier, s: start, e: end } = item;
|
|
44
70
|
// replace npm package to CDN url for matched imports
|
|
45
|
-
if (specifier
|
|
46
|
-
|
|
47
|
-
|
|
71
|
+
if (specifier) {
|
|
72
|
+
const replacement =
|
|
73
|
+
// search from local scan matches first (for alias)
|
|
74
|
+
(importmatches[specifier] &&
|
|
75
|
+
importmap.imports[importmatches[specifier]]) ||
|
|
76
|
+
// search from esmi analyze result
|
|
77
|
+
importmap.imports[specifier];
|
|
78
|
+
if (replacement) {
|
|
79
|
+
s !== null && s !== void 0 ? s : (s = new magic_string_1.default(source));
|
|
80
|
+
s.overwrite(start, end, replacement);
|
|
81
|
+
}
|
|
48
82
|
}
|
|
49
83
|
});
|
|
50
84
|
return (s === null || s === void 0 ? void 0 : s.toString()) || source;
|
|
@@ -78,7 +112,11 @@ function generatePkgData(api) {
|
|
|
78
112
|
name: 'default',
|
|
79
113
|
path: 'es/index.js',
|
|
80
114
|
from: '',
|
|
81
|
-
deps: Object.entries(api.appData.deps)
|
|
115
|
+
deps: Object.entries(api.appData.deps)
|
|
116
|
+
// only compile entry imports
|
|
117
|
+
.filter(([_, { matches }]) => matches.length)
|
|
118
|
+
// convert to esmi config
|
|
119
|
+
.map(([name, { version }]) => ({
|
|
82
120
|
name,
|
|
83
121
|
version,
|
|
84
122
|
usedMap: {
|
|
@@ -109,13 +147,30 @@ exports.default = (api) => {
|
|
|
109
147
|
});
|
|
110
148
|
// skip umi by default
|
|
111
149
|
delete api.appData.deps['umi'];
|
|
150
|
+
// FIXME: force include react & react-dom
|
|
151
|
+
api.appData.deps['react'].version = api.appData.react.version;
|
|
152
|
+
api.appData.deps['react-dom'] = {
|
|
153
|
+
version: api.appData.react.version,
|
|
154
|
+
matches: ['react-dom'],
|
|
155
|
+
subpaths: [],
|
|
156
|
+
};
|
|
112
157
|
const data = generatePkgData(api);
|
|
113
158
|
const deps = data.pkgInfo.exports.reduce((r, exp) => r.concat(exp.deps.map((dep) => dep.name)), []);
|
|
114
159
|
const hasNewDep = deps.some((i) => !importmap.imports[i]);
|
|
115
160
|
// update importmap from esm if there has new import
|
|
116
161
|
if (hasNewDep) {
|
|
117
|
-
// TODO: add local cache and restore
|
|
118
162
|
importmap = (_a = (yield service.getImportmap(data))) === null || _a === void 0 ? void 0 : _a.importMap;
|
|
163
|
+
// update matches map to dep name
|
|
164
|
+
importmatches = Object.keys(api.appData.deps).reduce((r, dep) => {
|
|
165
|
+
// filter subpath imports
|
|
166
|
+
if (!api.appData.deps[dep].subpaths.length) {
|
|
167
|
+
// map all matches to dep name
|
|
168
|
+
api.appData.deps[dep].matches.forEach((m) => {
|
|
169
|
+
r[m] = dep;
|
|
170
|
+
});
|
|
171
|
+
}
|
|
172
|
+
return r;
|
|
173
|
+
}, {});
|
|
119
174
|
// because we will replaced package name to CDN url in vite plugin
|
|
120
175
|
// so we must append scope rules for the CDN url like the import specifier
|
|
121
176
|
// example:
|
|
@@ -136,7 +191,10 @@ exports.default = (api) => {
|
|
|
136
191
|
key: 'esmi',
|
|
137
192
|
config: {
|
|
138
193
|
schema(Joi) {
|
|
139
|
-
return Joi.object(
|
|
194
|
+
return Joi.object({
|
|
195
|
+
cdnOrigin: Joi.string(),
|
|
196
|
+
shimUrl: Joi.string(),
|
|
197
|
+
});
|
|
140
198
|
},
|
|
141
199
|
},
|
|
142
200
|
enableBy: api.EnableBy.config,
|
|
@@ -151,7 +209,10 @@ exports.default = (api) => {
|
|
|
151
209
|
api.onBeforeCompiler(() => __awaiter(void 0, void 0, void 0, function* () {
|
|
152
210
|
if (api.args.vite) {
|
|
153
211
|
// init esmi service
|
|
154
|
-
service = new Service_1.default({
|
|
212
|
+
service = new Service_1.default({
|
|
213
|
+
cdnOrigin: api.config.esmi.cdnOrigin,
|
|
214
|
+
cacheDir: (0, path_1.join)(api.cwd, '.esmi'),
|
|
215
|
+
});
|
|
155
216
|
// init project resolver
|
|
156
217
|
resolver = (0, scan_1.createResolver)({
|
|
157
218
|
alias: api.config.alias,
|
|
@@ -162,10 +223,17 @@ exports.default = (api) => {
|
|
|
162
223
|
}));
|
|
163
224
|
// append ipmortmap script for HTML
|
|
164
225
|
api.modifyHTML(($) => {
|
|
165
|
-
const scp = $('<script type="importmap"></script
|
|
226
|
+
const scp = $('<script type="importmap"></script>\n');
|
|
166
227
|
scp.html(JSON.stringify(importmap, null, 2));
|
|
167
228
|
$('head > script:eq(0)').before(scp);
|
|
168
|
-
//
|
|
229
|
+
// append importmap shim script
|
|
230
|
+
if (api.config.esmi.shimUrl) {
|
|
231
|
+
$('body > script:eq(0)').before($(`<script src="${api.config.esmi.shimUrl}"></script>\n`));
|
|
232
|
+
}
|
|
233
|
+
// preload for importmap modules
|
|
234
|
+
Object.values(importmap.imports).forEach((url) => {
|
|
235
|
+
scp.before($(`<link rel="modulepreload" href="${url}" />\n`));
|
|
236
|
+
});
|
|
169
237
|
return $;
|
|
170
238
|
});
|
|
171
239
|
if (api.args.vite) {
|
|
@@ -178,6 +246,7 @@ exports.default = (api) => {
|
|
|
178
246
|
yield refreshImportMap();
|
|
179
247
|
// TODO: refresh page when importmap changed
|
|
180
248
|
}),
|
|
249
|
+
resolver,
|
|
181
250
|
}));
|
|
182
251
|
return memo;
|
|
183
252
|
});
|
|
@@ -53,6 +53,8 @@ exports.default = (api) => {
|
|
|
53
53
|
}
|
|
54
54
|
});
|
|
55
55
|
api.modifyHTMLFavicon((memo) => {
|
|
56
|
-
return
|
|
56
|
+
return api.appData.faviconFile
|
|
57
|
+
? `${api.config.publicPath}${api.appData.faviconFile}`
|
|
58
|
+
: memo;
|
|
57
59
|
});
|
|
58
60
|
};
|
|
@@ -3,11 +3,13 @@ import * as t from '@umijs/bundler-utils/compiled/babel/types';
|
|
|
3
3
|
import { IOpts } from './lowImport';
|
|
4
4
|
interface IPluginOpts {
|
|
5
5
|
opts: IOpts;
|
|
6
|
+
css: string;
|
|
6
7
|
}
|
|
7
8
|
export default function (): {
|
|
8
9
|
visitor: {
|
|
9
10
|
Identifier(path: Babel.NodePath<t.Identifier>, state: {
|
|
10
11
|
opts: IPluginOpts;
|
|
12
|
+
file: any;
|
|
11
13
|
}): void;
|
|
12
14
|
MemberExpression(path: Babel.NodePath<t.MemberExpression>, state: {
|
|
13
15
|
opts: IPluginOpts;
|