@umijs/preset-umi 4.0.0-beta.11 → 4.0.0-beta.12

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.
@@ -1,4 +1,13 @@
1
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
+ };
2
11
  Object.defineProperty(exports, "__esModule", { value: true });
3
12
  const utils_1 = require("@umijs/utils");
4
13
  exports.default = (api) => {
@@ -6,14 +15,16 @@ exports.default = (api) => {
6
15
  name: 'setup',
7
16
  description: 'setup project',
8
17
  fn() {
9
- // generate tmp files
10
- utils_1.logger.info('generate files');
11
- api.applyPlugins({
12
- key: 'onGenerateFiles',
13
- args: {
14
- files: null,
15
- isFirstTime: false,
16
- },
18
+ return __awaiter(this, void 0, void 0, function* () {
19
+ // generate tmp files
20
+ utils_1.logger.info('generate files');
21
+ yield api.applyPlugins({
22
+ key: 'onGenerateFiles',
23
+ args: {
24
+ files: null,
25
+ isFirstTime: false,
26
+ },
27
+ });
17
28
  });
18
29
  },
19
30
  });
@@ -0,0 +1,56 @@
1
+ import type { IApi } from '../../types';
2
+ export interface IImportmapData {
3
+ importMap: {
4
+ imports: Record<string, string>;
5
+ scopes: Record<string, any>;
6
+ };
7
+ deps: {
8
+ name: string;
9
+ version: string;
10
+ type: string;
11
+ }[];
12
+ }
13
+ export interface IPkgData {
14
+ pkgJsonContent: IApi['pkg'];
15
+ pkgInfo: {
16
+ name: string;
17
+ version: string;
18
+ type: 'esm';
19
+ exports: {
20
+ name: string;
21
+ path: string;
22
+ from: string;
23
+ deps: {
24
+ name: string;
25
+ version: string;
26
+ usedMap: Record<string, {
27
+ usedNamespace?: boolean;
28
+ usedDefault?: boolean;
29
+ usedNames: string[];
30
+ }>;
31
+ }[];
32
+ }[];
33
+ assets: any[];
34
+ };
35
+ }
36
+ /**
37
+ * class for connect esmi server
38
+ */
39
+ export default class ESMIService {
40
+ cdnOrigin: string;
41
+ constructor(opts: {
42
+ cdnOrigin: string;
43
+ });
44
+ /**
45
+ * build importmap from deps tree
46
+ * @param data package data
47
+ * @returns ticketId
48
+ */
49
+ build(data: IPkgData): Promise<string | undefined>;
50
+ /**
51
+ * get importmap from deps tree
52
+ * @param data package data
53
+ * @returns importmap
54
+ */
55
+ getImportmap(data: IPkgData): Promise<IImportmapData | undefined>;
56
+ }
@@ -0,0 +1,54 @@
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 utils_1 = require("@umijs/utils");
13
+ /**
14
+ * class for connect esmi server
15
+ */
16
+ class ESMIService {
17
+ constructor(opts) {
18
+ this.cdnOrigin = '';
19
+ this.cdnOrigin = opts.cdnOrigin;
20
+ }
21
+ /**
22
+ * build importmap from deps tree
23
+ * @param data package data
24
+ * @returns ticketId
25
+ */
26
+ build(data) {
27
+ return __awaiter(this, void 0, void 0, function* () {
28
+ return utils_1.axios
29
+ .post(`${this.cdnOrigin}/api/v1/esm/build`, data)
30
+ .then((a) => { var _a; return (_a = a.data.data) === null || _a === void 0 ? void 0 : _a.ticketId; });
31
+ });
32
+ }
33
+ /**
34
+ * get importmap from deps tree
35
+ * @param data package data
36
+ * @returns importmap
37
+ */
38
+ getImportmap(data) {
39
+ return __awaiter(this, void 0, void 0, function* () {
40
+ // get the build ticket id
41
+ const ticketId = yield this.build(data);
42
+ // continue to the next request after 1s
43
+ const next = () => new Promise((resolve) => setTimeout(() => resolve(deferrer()), 2000));
44
+ const deferrer = () => {
45
+ return utils_1.axios
46
+ .get(`${this.cdnOrigin}/api/v1/esm/importmap/${ticketId}`)
47
+ .then((res) => (res.data.success ? res.data.data : next()), next);
48
+ };
49
+ // TODO: timeout + time spend log
50
+ return deferrer();
51
+ });
52
+ }
53
+ }
54
+ exports.default = ESMIService;
@@ -1,3 +1,3 @@
1
- import { IApi } from '../../types';
1
+ import type { IApi } from '../../types';
2
2
  declare const _default: (api: IApi) => void;
3
3
  export default _default;
@@ -8,10 +8,130 @@ 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 });
15
+ const es_module_lexer_1 = require("@umijs/bundler-utils/compiled/es-module-lexer");
16
+ const magic_string_1 = __importDefault(require("magic-string"));
12
17
  const path_1 = require("path");
13
18
  const scan_1 = require("../../libs/scan");
19
+ const Service_1 = __importDefault(require("./Service"));
20
+ let importmap = { imports: {}, scopes: {} };
21
+ /**
22
+ * esmi vite plugin
23
+ */
24
+ function esmi(opts) {
25
+ return {
26
+ name: 'preset-umi:esmi',
27
+ configResolved(config) {
28
+ const { include, exclude } = config.optimizeDeps;
29
+ // do not pre-compile deps which will be loaded by importmap (for top-level deps)
30
+ if (include === null || include === void 0 ? void 0 : include.length) {
31
+ config.optimizeDeps.include = include.filter((item) => !importmap.imports[item]);
32
+ }
33
+ // exclude pre-compile deps which within importmap by default (for nested deps)
34
+ config.optimizeDeps.exclude = (exclude || []).concat(Object.keys(importmap.imports).filter((item) => exclude === null || exclude === void 0 ? void 0 : exclude.includes(item)));
35
+ },
36
+ transform(source) {
37
+ try {
38
+ // parse imports
39
+ const imports = (0, es_module_lexer_1.parse)(source)[0];
40
+ let s;
41
+ // process all imports
42
+ imports.forEach((item) => {
43
+ const { n: specifier, s: start, e: end } = item;
44
+ // replace npm package to CDN url for matched imports
45
+ if (specifier && importmap.imports[specifier]) {
46
+ s !== null && s !== void 0 ? s : (s = new magic_string_1.default(source));
47
+ s.overwrite(start, end, importmap.imports[specifier]);
48
+ }
49
+ });
50
+ return (s === null || s === void 0 ? void 0 : s.toString()) || source;
51
+ }
52
+ catch (_a) {
53
+ // syntax error or non-javascript files
54
+ return null;
55
+ }
56
+ },
57
+ handleHotUpdate(ctx) {
58
+ return opts.handleHotUpdate(ctx);
59
+ },
60
+ };
61
+ }
62
+ /**
63
+ * generate package data
64
+ * @param api plugin api
65
+ */
66
+ function generatePkgData(api) {
67
+ return {
68
+ pkgJsonContent: {
69
+ dependencies: api.pkg.dependencies || {},
70
+ devDependencies: api.pkg.devDependencies || {},
71
+ },
72
+ pkgInfo: {
73
+ name: api.pkg.name,
74
+ version: api.pkg.version,
75
+ type: 'esm',
76
+ exports: [
77
+ {
78
+ name: 'default',
79
+ path: 'es/index.js',
80
+ from: '',
81
+ deps: Object.entries(api.appData.deps).map(([name, version]) => ({
82
+ name,
83
+ version,
84
+ usedMap: {
85
+ [name]: { usedNamespace: true, usedNames: [] },
86
+ },
87
+ })),
88
+ },
89
+ ],
90
+ assets: [],
91
+ },
92
+ };
93
+ }
14
94
  exports.default = (api) => {
95
+ let service;
96
+ let resolver;
97
+ /**
98
+ * refresh importmap and save to the top-level variable
99
+ */
100
+ function refreshImportMap() {
101
+ var _a;
102
+ return __awaiter(this, void 0, void 0, function* () {
103
+ // scan and module graph
104
+ // TODO: module graph
105
+ api.appData.deps = yield (0, scan_1.scan)({
106
+ entry: (0, path_1.join)(api.paths.absTmpPath, 'umi.ts'),
107
+ externals: api.config.externals,
108
+ resolver,
109
+ });
110
+ // skip umi by default
111
+ delete api.appData.deps['umi'];
112
+ const data = generatePkgData(api);
113
+ const deps = data.pkgInfo.exports.reduce((r, exp) => r.concat(exp.deps.map((dep) => dep.name)), []);
114
+ const hasNewDep = deps.some((i) => !importmap.imports[i]);
115
+ // update importmap from esm if there has new import
116
+ if (hasNewDep) {
117
+ // TODO: add local cache and restore
118
+ importmap = (_a = (yield service.getImportmap(data))) === null || _a === void 0 ? void 0 : _a.importMap;
119
+ // because we will replaced package name to CDN url in vite plugin
120
+ // so we must append scope rules for the CDN url like the import specifier
121
+ // example:
122
+ // origin:
123
+ // { imports: { a: 'aa', b: 'bb', c: 'cc1' }, scopes: { b: { c: 'cc2' } } }
124
+ // to:
125
+ // { imports: { a: 'aa', b: 'bb', c: 'cc1' }, scopes: { b: { c: 'cc2' }, 'bb': { c: 'cc2' } } }
126
+ Object.keys(importmap.scopes || {})
127
+ .filter((item) => importmap.imports[item])
128
+ .forEach((item) => {
129
+ importmap.scopes[importmap.imports[item]] = importmap.scopes[item];
130
+ });
131
+ }
132
+ });
133
+ }
134
+ // describe config
15
135
  api.describe({
16
136
  key: 'esmi',
17
137
  config: {
@@ -21,24 +141,48 @@ exports.default = (api) => {
21
141
  },
22
142
  enableBy: api.EnableBy.config,
23
143
  });
144
+ // check bundler type
24
145
  api.onStart(() => {
25
146
  if (!api.args.vite) {
26
147
  throw new Error(`esmi can only be used in vite mode.`);
27
148
  }
28
149
  });
29
- // 需要在 generate 之后是因为需要先等临时文件生成
150
+ // collect all imports after tmp files generated
30
151
  api.onBeforeCompiler(() => __awaiter(void 0, void 0, void 0, function* () {
31
- // scan and module graph
32
- // TODO: module graph
33
152
  if (api.args.vite) {
34
- const resolver = (0, scan_1.createResolver)({
153
+ // init esmi service
154
+ service = new Service_1.default({ cdnOrigin: api.config.esmi.cdnOrigin });
155
+ // init project resolver
156
+ resolver = (0, scan_1.createResolver)({
35
157
  alias: api.config.alias,
36
158
  });
37
- api.appData.deps = yield (0, scan_1.scan)({
38
- entry: (0, path_1.join)(api.paths.absTmpPath, 'umi.ts'),
39
- externals: api.config.externals,
40
- resolver,
41
- });
159
+ // init importmap
160
+ yield refreshImportMap();
42
161
  }
43
162
  }));
163
+ // append ipmortmap script for HTML
164
+ api.modifyHTML(($) => {
165
+ const scp = $('<script type="importmap"></script>');
166
+ scp.html(JSON.stringify(importmap, null, 2));
167
+ $('head > script:eq(0)').before(scp);
168
+ // TODO: polyfill for legacy browser
169
+ return $;
170
+ });
171
+ if (api.args.vite) {
172
+ // apply esmi vite plugin
173
+ api.modifyViteConfig((memo) => {
174
+ memo.plugins = (memo.plugins || []).concat(esmi({
175
+ handleHotUpdate: (ctx) => __awaiter(void 0, void 0, void 0, function* () {
176
+ ctx.file;
177
+ // TODO: incremental refresh by ctx.file
178
+ yield refreshImportMap();
179
+ // TODO: refresh page when importmap changed
180
+ }),
181
+ }));
182
+ return memo;
183
+ });
184
+ }
185
+ else {
186
+ // TODO: webpack implementation
187
+ }
44
188
  };
@@ -24,8 +24,8 @@ function default_1(api) {
24
24
  });
25
25
  },
26
26
  },
27
- enableBy({ env }) {
28
- return env === 'development';
27
+ enableBy() {
28
+ return api.name === 'dev';
29
29
  },
30
30
  });
31
31
  // context for update mockData
@@ -27,6 +27,7 @@ exports.default = (api) => {
27
27
  api.onGenerateFiles((opts) => __awaiter(void 0, void 0, void 0, function* () {
28
28
  // umi.ts
29
29
  api.writeTmpFile({
30
+ noPluginDir: true,
30
31
  path: 'umi.ts',
31
32
  tplPath: (0, path_1.join)(constants_1.TEMPLATES_DIR, 'umi.tpl'),
32
33
  context: {
@@ -70,6 +71,7 @@ exports.default = (api) => {
70
71
  // @/pages/
71
72
  const prefix = hasSrc ? '../../../src/pages/' : '../../pages/';
72
73
  api.writeTmpFile({
74
+ noPluginDir: true,
73
75
  path: 'core/route.ts',
74
76
  tplPath: (0, path_1.join)(constants_1.TEMPLATES_DIR, 'route.tpl'),
75
77
  context: {
@@ -110,6 +112,7 @@ exports.default = (api) => {
110
112
  ],
111
113
  });
112
114
  api.writeTmpFile({
115
+ noPluginDir: true,
113
116
  path: 'core/plugin.ts',
114
117
  tplPath: (0, path_1.join)(constants_1.TEMPLATES_DIR, 'plugin.tpl'),
115
118
  context: {
@@ -60,7 +60,9 @@ exports.default = (api) => {
60
60
  name: 'writeTmpFile',
61
61
  fn(opts) {
62
62
  (0, assert_1.default)(api.service.stage >= api.ServiceStage.runCommand, `api.writeTmpFile() should not execute in register stage.`);
63
- const absPath = (0, path_1.join)(api.paths.absTmpPath, opts.path);
63
+ const absPath = (0, path_1.join)(api.paths.absTmpPath,
64
+ // @ts-ignore
65
+ this.plugin.key && !opts.noPluginDir ? `plugin-${this.plugin.key}` : '', opts.path);
64
66
  utils_1.fsExtra.mkdirpSync((0, path_1.dirname)(absPath));
65
67
  let content = opts.content;
66
68
  if (!content) {
@@ -77,7 +79,8 @@ exports.default = (api) => {
77
79
  (0, isTypeScriptFile_1.isTypeScriptFile)(opts.path) && `// @ts-nocheck`,
78
80
  '// This file is generated by Umi automatically',
79
81
  '// DO NOT CHANGE IT MANUALLY!',
80
- content,
82
+ content.trim(),
83
+ '',
81
84
  ]
82
85
  .filter((text) => text !== false)
83
86
  .join('\n');
package/dist/types.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  import type { RequestHandler } from '@umijs/bundler-webpack';
2
2
  import type webpack from '@umijs/bundler-webpack/compiled/webpack';
3
3
  import type WebpackChain from '@umijs/bundler-webpack/compiled/webpack-5-chain';
4
+ import type { InlineConfig as ViteInlineConfig } from 'vite';
4
5
  import type { IAdd, IEvent, IModify, IRoute as ICoreRoute, IServicePluginAPI, PluginAPI } from '@umijs/core';
5
6
  import { Env } from '@umijs/core';
6
7
  import type { CheerioAPI } from '@umijs/utils/compiled/cheerio';
@@ -48,6 +49,7 @@ export declare type IApi = PluginAPI & IServicePluginAPI & {
48
49
  restartServer: () => void;
49
50
  writeTmpFile: (opts: {
50
51
  path: string;
52
+ noPluginDir?: boolean;
51
53
  content?: string;
52
54
  tpl?: string;
53
55
  tplPath?: string;
@@ -133,7 +135,7 @@ export declare type IApi = PluginAPI & IServicePluginAPI & {
133
135
  webpack: typeof webpack;
134
136
  env: Env;
135
137
  }>;
136
- modifyViteConfig: IModify<webpack.Configuration, {
138
+ modifyViteConfig: IModify<ViteInlineConfig, {
137
139
  env: Env;
138
140
  }>;
139
141
  chainWebpack: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@umijs/preset-umi",
3
- "version": "4.0.0-beta.11",
3
+ "version": "4.0.0-beta.12",
4
4
  "description": "@umijs/preset-umi",
5
5
  "homepage": "https://github.com/umijs/umi-next/tree/master/packages/preset-umi#readme",
6
6
  "bugs": "https://github.com/umijs/umi-next/issues",
@@ -24,28 +24,30 @@
24
24
  },
25
25
  "dependencies": {
26
26
  "@types/multer": "1.4.7",
27
- "@umijs/ast": "4.0.0-beta.11",
28
- "@umijs/babel-preset-umi": "4.0.0-beta.11",
29
- "@umijs/bundler-utils": "4.0.0-beta.11",
30
- "@umijs/bundler-vite": "4.0.0-beta.11",
31
- "@umijs/bundler-webpack": "4.0.0-beta.11",
32
- "@umijs/core": "4.0.0-beta.11",
33
- "@umijs/renderer-react": "4.0.0-beta.11",
34
- "@umijs/server": "4.0.0-beta.11",
35
- "@umijs/utils": "4.0.0-beta.11",
27
+ "@umijs/ast": "4.0.0-beta.12",
28
+ "@umijs/babel-preset-umi": "4.0.0-beta.12",
29
+ "@umijs/bundler-utils": "4.0.0-beta.12",
30
+ "@umijs/bundler-vite": "4.0.0-beta.12",
31
+ "@umijs/bundler-webpack": "4.0.0-beta.12",
32
+ "@umijs/core": "4.0.0-beta.12",
33
+ "@umijs/renderer-react": "4.0.0-beta.12",
34
+ "@umijs/server": "4.0.0-beta.12",
35
+ "@umijs/utils": "4.0.0-beta.12",
36
36
  "current-script-polyfill": "1.0.0",
37
37
  "enhanced-resolve": "5.8.3",
38
+ "magic-string": "0.25.7",
38
39
  "path-to-regexp": "1.7.0",
39
40
  "react": "18.0.0-alpha-f2c381131-20211004",
40
41
  "react-dom": "18.0.0-alpha-f2c381131-20211004",
41
- "react-router": "6.0.0-beta.7",
42
- "react-router-dom": "6.0.0-beta.7"
42
+ "react-router": "6.0.2",
43
+ "react-router-dom": "6.0.2"
43
44
  },
44
45
  "devDependencies": {
45
46
  "@types/body-parser": "1.19.2",
46
47
  "@types/multer": "1.4.7",
47
48
  "body-parser": "1.19.0",
48
- "multer": "1.4.3"
49
+ "multer": "1.4.3",
50
+ "vite": "2.6.13"
49
51
  },
50
52
  "publishConfig": {
51
53
  "access": "public"