From e80e805a1ba26855df505fcbb95a44a63b94015d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?chencheng=20=28=E4=BA=91=E8=B0=A6=29?= Date: Thu, 19 Oct 2023 19:10:48 +0800 Subject: [PATCH 01/19] fix: overrides might be empty (#11768) --- packages/preset-umi/src/features/overrides/overrides.ts | 2 +- packages/preset-umi/src/features/overrides/transform.ts | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/preset-umi/src/features/overrides/overrides.ts b/packages/preset-umi/src/features/overrides/overrides.ts index fe8b160caaa2..1f97ba1dcd97 100644 --- a/packages/preset-umi/src/features/overrides/overrides.ts +++ b/packages/preset-umi/src/features/overrides/overrides.ts @@ -31,7 +31,7 @@ export default (api: IApi) => { content = await transform(content, filePath); api.writeTmpFile({ path: 'core/overrides.css', - content, + content: content || '/* empty */', noPluginDir: true, }); cachedContent = content; diff --git a/packages/preset-umi/src/features/overrides/transform.ts b/packages/preset-umi/src/features/overrides/transform.ts index b33fa4ac7064..a352e9ebf4c5 100644 --- a/packages/preset-umi/src/features/overrides/transform.ts +++ b/packages/preset-umi/src/features/overrides/transform.ts @@ -54,6 +54,8 @@ export async function transform(cssContent: string, filePath: string) { const result = await require('postcss')([ selectorPlugin, importPlugin, - ]).process(cssContent, {}); + ]).process(cssContent, { + from: 'overrides.css', + }); return result.css; } From 352b0a8bc2620df29a5f43d984e0c654344defea Mon Sep 17 00:00:00 2001 From: pshu Date: Thu, 2 Nov 2023 09:07:42 +0800 Subject: [PATCH 02/19] =?UTF-8?q?feat:=20=E2=9C=A8=20testing=20=E6=94=AF?= =?UTF-8?q?=E6=8C=81=20mjs=20=E6=96=87=E4=BB=B6=20(#11818)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- examples/test-test/utils/mjs.mjs | 3 +++ examples/test-test/utils/mjs.test.ts | 5 +++++ packages/testing/src/index.ts | 4 ++++ .../testing/src/transformers/esbuild/index.ts | 18 ++++++++++++++++-- 4 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 examples/test-test/utils/mjs.mjs create mode 100644 examples/test-test/utils/mjs.test.ts diff --git a/examples/test-test/utils/mjs.mjs b/examples/test-test/utils/mjs.mjs new file mode 100644 index 000000000000..c874d5ad9aad --- /dev/null +++ b/examples/test-test/utils/mjs.mjs @@ -0,0 +1,3 @@ +export default function mjs() { + return 'mjs' +}; diff --git a/examples/test-test/utils/mjs.test.ts b/examples/test-test/utils/mjs.test.ts new file mode 100644 index 000000000000..2fd212b31203 --- /dev/null +++ b/examples/test-test/utils/mjs.test.ts @@ -0,0 +1,5 @@ +import mjs from './mjs.mjs'; + +it('imports from mjs', () => { + expect(mjs()).toBe('mjs'); +}); diff --git a/packages/testing/src/index.ts b/packages/testing/src/index.ts index 3d2e1fd7a1fa..aab459daa631 100644 --- a/packages/testing/src/index.ts +++ b/packages/testing/src/index.ts @@ -73,6 +73,10 @@ export function createConfig(opts?: { opts?.jsTransformer || 'esbuild', opts?.jsTransformerOpts, ), + '^.+\\.mjs$': getJSTransformer( + opts?.jsTransformer || 'esbuild', + opts?.jsTransformerOpts, + ), }, moduleNameMapper: { '^.+\\.(css|less|sass|scss|stylus)$': diff --git a/packages/testing/src/transformers/esbuild/index.ts b/packages/testing/src/transformers/esbuild/index.ts index dfd22f7743e6..daed4d76694a 100644 --- a/packages/testing/src/transformers/esbuild/index.ts +++ b/packages/testing/src/transformers/esbuild/index.ts @@ -11,7 +11,9 @@ const TS_TSX_REGEX = /\.tsx?$/; const JS_JSX_REGEX = /\.jsx?$/; function isTarget(path: string) { - return JS_JSX_REGEX.test(path) || TS_TSX_REGEX.test(path); + return ( + JS_JSX_REGEX.test(path) || TS_TSX_REGEX.test(path) || path.endsWith('.mjs') + ); } const createTransformer = ( @@ -70,7 +72,7 @@ const createTransformer = ( const result = transformSync(rawCode, { ...options, ...(config.globals['jest-esbuild'] as UserOptions), - loader: userOptions.loader || (extname(path).slice(1) as Loader), + loader: userOptions.loader || ext2Loader(extname(path)), sourcefile: path, sourcesContent: false, }); @@ -100,6 +102,18 @@ const createTransformer = ( }; }; +const EXT_MAP: Record = { + '.js': 'js', + '.jsx': 'jsx', + '.ts': 'ts', + '.tsx': 'tsx', + '.mjs': 'js', +}; + +function ext2Loader(ext: string): Loader { + return EXT_MAP[ext] || 'js'; +} + export default { createTransformer, }; From 9ce9266a322078f40af23902356b47d8dcc7a6d9 Mon Sep 17 00:00:00 2001 From: money Date: Thu, 2 Nov 2023 14:51:27 +0800 Subject: [PATCH 03/19] docs: correct highlight for navigation items (#11810) --- docs/.dumirc.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/docs/.dumirc.ts b/docs/.dumirc.ts index 018fb057f36c..9a629d704079 100644 --- a/docs/.dumirc.ts +++ b/docs/.dumirc.ts @@ -44,22 +44,27 @@ export default defineConfig({ { title: '介绍', link: '/docs/introduce/introduce', + activePath: '/docs/introduce', }, { title: '指南', link: '/docs/guides/getting-started', + activePath: '/docs/guides', }, { title: 'API', link: '/docs/api/api', + activePath: '/docs/api', }, { title: 'Umi Max', link: '/docs/max/introduce', + activePath: '/docs/max', }, { title: '博客', link: '/blog/umi-4-rc', + activePath: '/blog', }, ], }, From 553711aba7d20b0daa31055a36d6a4e248856058 Mon Sep 17 00:00:00 2001 From: gwuhaolin Date: Thu, 2 Nov 2023 16:00:04 +0800 Subject: [PATCH 04/19] =?UTF-8?q?fix(SSR):=20=E9=98=B2=E6=AD=A2=E5=A4=9Ach?= =?UTF-8?q?unk=E6=83=85=E5=86=B5=E4=B8=8B=EF=BC=88=E6=9C=89=E6=87=92?= =?UTF-8?q?=E5=8A=A0=E8=BD=BD=E6=97=B6=EF=BC=89=E7=9A=84=E6=96=87=E4=BB=B6?= =?UTF-8?q?=E5=90=8D=E5=86=B2=E7=AA=81=E6=8A=A5=E9=94=99=20(#11823)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: dev环境构建SSR server.js时,环境判断错误导致输出的dev产物带上了hash * Update packages/preset-umi/src/features/ssr/webpack/webpack.ts Co-authored-by: chencheng (云谦) * fix: dev环境构建SSR server.js时,环境判断错误导致输出的dev产物带上了hash * feature: 支持自定义SSR构建目标,默认为node,可配置为webworker以支持运行在类似Cloudflare Workers的平台 以解决 react-dom/server renderToReadableStream 不存在的问题 * feature: getManifest支持传入sourceDir表示SSR产物目录 * feature: getManifest支持传入sourceDir表示SSR产物目录 * fix: rendertoreadablestream is not a function * Revert "feature: 支持自定义SSR构建目标,默认为node,可配置为webworker以支持运行在类似Cloudflare Workers的平台" This reverts commit 5b0946a70121a8f5c7332e70bd0aa4da904253e8. * fix: rendertoreadablestream is not a function * Update packages/server/src/ssr.ts Co-authored-by: 咲奈Sakina <59400654+fz6m@users.noreply.github.com> * Update packages/server/src/ssr.ts Co-authored-by: 咲奈Sakina <59400654+fz6m@users.noreply.github.com> * fix: 还原g_getAssets * fix: 被执行时才调用getManifest(),避免在入口立即调用getManifest() * fix: 被执行时才调用getManifest(),避免在入口立即调用getManifest() * fix: 被执行时才调用getManifest(),避免在入口立即调用getManifest() * feature: SSR模式下,多输出一份和index.html完全一致的*.html文件,用于ER场景 * feature: SSR模式下,多输出一份和index.html完全一致的*.html文件,用于ER场景 * fix: SSR withoutHTML模式下,包一层
{app}
* fix: 回滚SSR模式下,多输出一份和index.html完全一致的*.html文件,用于ER场景 * fix: SSR withoutHTML模式下也需要注入loaderData数据用于注水时 * fix: 在有basename的情况下__serverLoader的请求路径需要加上basename * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * fix: async 函数返回值不需要 await ,不然会多造成一次异步成本。 * fix: 在请求__serverLoader时,带上cookie,以实现在SSR时请求需要登入态的接口 * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * fix: dumi 里做 ssg 时传的 path 是不带 host 的,需要加上host * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * feature: 支持在serverLoader中读取当前request,以实现在serverLoader中读取url中的参数和headers * fix: 防止多chunk情况下(有懒加载时)的文件名冲突报错 * fix: 防止多chunk情况下(有懒加载时)的文件名冲突报错 * Update packages/preset-umi/src/features/ssr/webpack/webpack.ts --------- Co-authored-by: 奇风 Co-authored-by: chencheng (云谦) Co-authored-by: 咲奈Sakina <59400654+fz6m@users.noreply.github.com> --- packages/preset-umi/src/features/ssr/webpack/webpack.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/preset-umi/src/features/ssr/webpack/webpack.ts b/packages/preset-umi/src/features/ssr/webpack/webpack.ts index dd527d58f88f..687caf4fbec3 100644 --- a/packages/preset-umi/src/features/ssr/webpack/webpack.ts +++ b/packages/preset-umi/src/features/ssr/webpack/webpack.ts @@ -46,9 +46,10 @@ export const build = async (api: IApi, opts: any) => { memo.output .path(dirname(absOutputFile)) - .filename(useHash ? 'umi.[contenthash:8].server.js' : 'umi.server.js') + // 避免多 chunk 时的命名冲突,虽然 ssr 在项目里禁用了 import() 语法,但 node_modules 下可能存在的 import() 没有被 babel 插件覆盖到 + .filename(useHash ? '[name].[contenthash:8].server.js' : '[name].server.js') .chunkFilename( - useHash ? 'umi.[contenthash:8].server.js' : 'umi.server.js', + useHash ? '[name].[contenthash:8].server.js' : '[name].server.js', ) .libraryTarget('commonjs2'); From a8303837e2f33c8a82642b302ac57cf367af1bee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=B8=85?= Date: Sat, 4 Nov 2023 08:40:07 -0500 Subject: [PATCH 05/19] fix(ssr): support ant design pro ssr (#11702) --- examples/ant-design-pro/config/config.ts | 25 +++-------- .../bundler-webpack/src/config/ssrPlugin.ts | 11 +++-- .../src/features/exportStatic/exportStatic.ts | 5 ++- packages/server/src/ssr.ts | 41 ++++++++++++------- 4 files changed, 44 insertions(+), 38 deletions(-) diff --git a/examples/ant-design-pro/config/config.ts b/examples/ant-design-pro/config/config.ts index 9537b4cf3432..82972dc7bb4b 100644 --- a/examples/ant-design-pro/config/config.ts +++ b/examples/ant-design-pro/config/config.ts @@ -313,28 +313,15 @@ export default defineConfig({ mfsu: { // esbuild: true, }, - chainWebpack(memo: any) { + chainWebpack(memo) { memo.plugin('monaco-editor').use(MonacoEditorWebpackPlugin, []); return memo; }, - // openAPI: [ - // { - // requestLibPath: "import { request } from 'umi'", - // // 或者使用在线的版本 - // // schemaPath: "https://gw.alipayobjects.com/os/antfincdn/M%24jrzTTYJN/oneapi.json" - // schemaPath: join(__dirname, 'oneapi.json'), - // mock: false, - // }, - // { - // requestLibPath: "import { request } from 'umi'", - // schemaPath: 'https://gw.alipayobjects.com/os/antfincdn/CA1dOm%2631B/openapi.json', - // projectName: 'swagger', - // }, - // ], - // nodeModulesTransform: { - // type: 'none', - // }, - // exportStatic: {}, + ssr: { + builder: 'webpack', + platform: 'node', + }, + exportStatic: {}, codeSplitting: { jsStrategy: 'granularChunks', }, diff --git a/packages/bundler-webpack/src/config/ssrPlugin.ts b/packages/bundler-webpack/src/config/ssrPlugin.ts index 0c2b5c473316..21b987744eb5 100644 --- a/packages/bundler-webpack/src/config/ssrPlugin.ts +++ b/packages/bundler-webpack/src/config/ssrPlugin.ts @@ -1,6 +1,6 @@ import type { - Compiler, Compilation, + Compiler, } from '@umijs/bundler-webpack/compiled/webpack'; import { sources } from '@umijs/bundler-webpack/compiled/webpack'; import { fsExtra } from '@umijs/utils'; @@ -23,9 +23,11 @@ const PLUGIN_NAME = 'SSR_PLUGIN'; class SSRPlugin { opts: IOpts; manifest: Map; + isGenManifest: boolean; constructor(opts: IOpts) { this.opts = opts; this.manifest = new Map(); + this.isGenManifest = false; } apply(compiler: Compiler) { // ref: https://github.com/webdeveric/webpack-assets-manifest @@ -70,13 +72,16 @@ class SSRPlugin { 2, ); if ( - process.env.NODE_ENV === 'production' || - this.opts.userConfig.writeToDisk + (process.env.NODE_ENV === 'production' || + this.opts.userConfig.writeToDisk) && + !this.isGenManifest ) { + // 如果已经生成了,就不管了。不然会报错重复添加 compilation.emitAsset( 'build-manifest.json', new sources.RawSource(assetsSource, false), ); + this.isGenManifest = true; } else { const outputPath = compiler.options.output.path!; fsExtra.mkdirpSync(outputPath); diff --git a/packages/preset-umi/src/features/exportStatic/exportStatic.ts b/packages/preset-umi/src/features/exportStatic/exportStatic.ts index 411a2b44e35d..864d3df9dbc4 100644 --- a/packages/preset-umi/src/features/exportStatic/exportStatic.ts +++ b/packages/preset-umi/src/features/exportStatic/exportStatic.ts @@ -31,10 +31,11 @@ function getExportHtmlData(routes: Record): IExportHtmlItem[] { if ( // skip layout !route.isLayout && + route?.path && // skip dynamic route for win, because `:` is not allowed in file name - (!IS_WIN || !route.path.includes('/:')) && + (!IS_WIN || !route?.path?.includes('/:')) && // skip `*` route, because `*` is not working for most site serve services - (!route.path.includes('*') || + (!route?.path?.includes('*') || // except `404.html` is404) ) { diff --git a/packages/server/src/ssr.ts b/packages/server/src/ssr.ts index e2312aae899f..56398612bdcd 100644 --- a/packages/server/src/ssr.ts +++ b/packages/server/src/ssr.ts @@ -95,14 +95,20 @@ function createJSXGenerator(opts: CreateRequestHandlerOptions) { .map( (id: string) => new Promise(async (resolve) => { - loaderData[id] = await executeLoader(id, routesWithServerLoader, serverLoaderArgs); + loaderData[id] = await executeLoader( + id, + routesWithServerLoader, + serverLoaderArgs, + ); resolve(); }), ), ); const manifest = - typeof opts.manifest === 'function' ? opts.manifest(sourceDir) : opts.manifest; + typeof opts.manifest === 'function' + ? opts.manifest(sourceDir) + : opts.manifest; const context = { routes, routeComponents, @@ -167,11 +173,11 @@ export function createMarkupGenerator(opts: CreateRequestHandlerOptions) { html = html.replace( /(<\/head>)/, [ - opts.helmetContext.helmet.title.toString(), - opts.helmetContext.helmet.priority.toString(), - opts.helmetContext.helmet.meta.toString(), - opts.helmetContext.helmet.link.toString(), - opts.helmetContext.helmet.script.toString(), + opts.helmetContext.helmet?.title?.toString(), + opts.helmetContext.helmet?.priority?.toString(), + opts.helmetContext.helmet?.meta?.toString(), + opts.helmetContext.helmet?.link?.toString(), + opts.helmetContext.helmet?.script?.toString(), '$1', ] .filter(Boolean) @@ -217,9 +223,12 @@ export default function createRequestHandler( return; } - const request = new Request(req.protocol + '://' + req.get('host') + req.originalUrl, { - headers: req.headers, - }); + const request = new Request( + req.protocol + '://' + req.get('host') + req.originalUrl, + { + headers: req.headers, + }, + ); const jsx = await jsxGeneratorDeferrer(req.url, { request }); if (!jsx) return next(); @@ -255,10 +264,12 @@ export function createUmiHandler(opts: CreateRequestHandlerOptions) { ...opts, ...params, }); - const jsx = await jsxGeneratorDeferrer(new URL(req.url).pathname, { request: req }); + const jsx = await jsxGeneratorDeferrer(new URL(req.url).pathname, { + request: req, + }); if (!jsx) { - throw new Error('no page resource') + throw new Error('no page resource'); } return ReactDomServer.renderToNodeStream(jsx.element); @@ -269,7 +280,9 @@ export function createUmiServerLoader(opts: CreateRequestHandlerOptions) { return async function (req: Request) { const query = Object.fromEntries(new URL(req.url).searchParams); // 切换路由场景下,会通过此 API 执行 server loader - return await executeLoader(query.route, opts.routesWithServerLoader, { request: req }); + return await executeLoader(query.route, opts.routesWithServerLoader, { + request: req, + }); }; } @@ -311,7 +324,7 @@ function createClientRoute(route: any) { async function executeLoader( routeKey: string, routesWithServerLoader: RouteLoaders, - serverLoaderArgs?: IServerLoaderArgs + serverLoaderArgs?: IServerLoaderArgs, ) { const mod = await routesWithServerLoader[routeKey](); if (!mod.serverLoader || typeof mod.serverLoader !== 'function') { From 1e4e66c79cbd5d77004dd6101ae67fa583b56fa8 Mon Sep 17 00:00:00 2001 From: money Date: Tue, 7 Nov 2023 05:28:42 +0800 Subject: [PATCH 06/19] docs: correct type (#11836) --- docs/docs/docs/api/config.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/docs/api/config.md b/docs/docs/docs/api/config.md index 0293ba80dc7e..4d3965b4e430 100644 --- a/docs/docs/docs/api/config.md +++ b/docs/docs/docs/api/config.md @@ -358,7 +358,7 @@ crossorigin: {} ## cssMinifierOptions -- 类型:`Object` +- 类型:`object` - 默认值:`{}` `cssMinifier` CSS 压缩工具配置选项。 @@ -904,7 +904,7 @@ import { Icon } from 'umi'; ## lessLoader -- 类型:`Object` +- 类型:`object` - 默认值:`{ modifyVars: userConfig.theme, javascriptEnabled: true }` 设置 less-loader 的 Options。具体参考参考 [less-loader 的 Options](https://github.com/webpack-contrib/less-loader#lessoptions)。 From 8a44f4f9bb5f8e1e1ec8a93ccd44c7b5f16055c6 Mon Sep 17 00:00:00 2001 From: Tao Zhou Date: Tue, 7 Nov 2023 05:32:12 +0800 Subject: [PATCH 07/19] docs: fix minor errors and improve readability (#11801) * docs: improve readability in introduce.md * docs: fix inconsistent capitalization in philosophy.md * docs: add a missing period in upgrade-to-umi-4.md * docs: improve readability in prepare.md * docs: fix punctuation inconsistency in directory-structure.md * docs: improve readability in routes.md * docs: fix typos and improve readability in mock.md * docs: improve readability in proxy.md * docs: fix a typo and improve readability in styling.md * docs: fix a typo and punctuation inconsistency in env-variables.md * docs: remove a redundant expression in boilerplate.md * docs: fix typos and improve readability in generator.md * docs: improve readability in debug.md * docs: fix a typo and improve readability in test.md * docs: fix punctuation inconsistency and improve readability in plugins.md * docs: add missing punctuation and improve readability in use-vue.md * docs: fix inconsistent capitalization and improve readability in mpa.md --- docs/docs/docs/guides/boilerplate.md | 2 +- docs/docs/docs/guides/debug.md | 2 +- docs/docs/docs/guides/directory-structure.md | 2 +- docs/docs/docs/guides/env-variables.md | 12 +++++----- docs/docs/docs/guides/generator.md | 12 +++++----- docs/docs/docs/guides/mock.md | 6 ++--- docs/docs/docs/guides/mpa.md | 6 ++--- docs/docs/docs/guides/plugins.md | 24 ++++++++++---------- docs/docs/docs/guides/prepare.md | 6 ++--- docs/docs/docs/guides/proxy.md | 4 ++-- docs/docs/docs/guides/routes.md | 6 ++--- docs/docs/docs/guides/styling.md | 6 ++--- docs/docs/docs/guides/test.md | 6 ++--- docs/docs/docs/guides/use-vue.md | 16 ++++++------- docs/docs/docs/introduce/introduce.md | 4 ++-- docs/docs/docs/introduce/philosophy.md | 2 +- docs/docs/docs/introduce/upgrade-to-umi-4.md | 2 +- 17 files changed, 59 insertions(+), 59 deletions(-) diff --git a/docs/docs/docs/guides/boilerplate.md b/docs/docs/docs/guides/boilerplate.md index e42253fb8e7a..cce4949bcf3b 100644 --- a/docs/docs/docs/guides/boilerplate.md +++ b/docs/docs/docs/guides/boilerplate.md @@ -10,7 +10,7 @@ Umi 官方提供了一个脚手架 ,可以轻松快速创建一个项目: pnpm dlx create-umi@latest ``` -这个命令会安装 `create-umi` 脚手架并自动运行,运行后提供了两个可选项可以选择: +这个命令会安装 `create-umi` 脚手架并自动运行,运行后提供了两个可选项: 1. Pick Npm Client - 选择 Npm 客户端 diff --git a/docs/docs/docs/guides/debug.md b/docs/docs/docs/guides/debug.md index 96fa4c297235..653a0052d394 100644 --- a/docs/docs/docs/guides/debug.md +++ b/docs/docs/docs/guides/debug.md @@ -9,7 +9,7 @@ toc: content ## 调试 dev 产物 -如果你需要在 dev 阶段调试项目的构建产物,以 `umi.js` 举例。先将原来的 `umi.js` 下载到当前项目根目录下。根据调试需要进行编辑后,刷新浏览器,项目使用的 `umi.js` 就替换成了根目录下的 `umi.js` 文件。调试完毕需要恢复就直接删除根目录的 `umi.js` 即可。 +如果你需要在 dev 阶段调试项目的构建产物,以 `umi.js` 举例。先将原来的 `umi.js` 下载到当前项目根目录下。根据调试需要进行编辑后,刷新浏览器,项目使用的 `umi.js` 就替换成了根目录下的 `umi.js` 文件。如果调试完毕需要恢复,直接删除根目录的 `umi.js` 即可。 举例: ```bash diff --git a/docs/docs/docs/guides/directory-structure.md b/docs/docs/docs/guides/directory-structure.md index 7d0046fd8b2a..6f6d68fc9df1 100644 --- a/docs/docs/docs/guides/directory-structure.md +++ b/docs/docs/docs/guides/directory-structure.md @@ -4,7 +4,7 @@ toc: content --- # 目录结构 -这里罗列了 Umi 项目中约定(或推荐)的目录结构,在项目开发中,请遵照这个目录结构组织代码。 +这里罗列了 Umi 项目中约定(或推荐)的目录结构,在项目开发中,请遵照这个目录结构组织代码。 ```bash . diff --git a/docs/docs/docs/guides/env-variables.md b/docs/docs/docs/guides/env-variables.md index 45ab401b1115..821142a2d486 100644 --- a/docs/docs/docs/guides/env-variables.md +++ b/docs/docs/docs/guides/env-variables.md @@ -10,7 +10,7 @@ Umi 可以通过环境变量来完成一些特殊的配置和功能。 ### 执行命令时设置 -例如需要改变 `umi dev` 开发服务器的端口,进可以通过如下命令实现。 +例如需要改变 `umi dev` 开发服务器的端口,可以通过如下命令实现。 ```bash # OS X, Linux @@ -20,7 +20,7 @@ $ PORT=3000 umi dev $ set PORT=3000&&umi dev ``` -如果需要同时在不同的操作系统中使用环境变量,推荐使用工具 [cross-env](https://github.com/kentcdodds/cross-env) +如果需要同时在不同的操作系统中使用环境变量,推荐使用工具 [cross-env](https://github.com/kentcdodds/cross-env)。 ```bash $ pnpm install cross-env -D @@ -78,7 +78,7 @@ CONCAT=$FOO$BAR # CONCAT=foobar 注意: -* APP_ROOT 不能配在 .env 中,只能在命令行里添加 +* `APP_ROOT` 不能配在 `.env` 中,只能在命令行里添加 ### ANALYZE @@ -101,7 +101,7 @@ $ ANALYZE=1 umi build ### COMPRESS -默认压缩 CSS 和 JS,值为 none 时不压缩,build 时有效。 +默认压缩 CSS 和 JS,值为 `none` 时不压缩,`build` 时有效。 ### DID_YOU_KNOW @@ -113,11 +113,11 @@ $ ANALYZE=1 umi build ### FS_LOGGER -默认会开启保存物理日志,值为 none 时不保存,同时针对 webcontainer 场景(比如 stackbliz)暂不保存。 +默认会开启保存物理日志,值为 `none` 时不保存,同时针对 webcontainer 场景(比如 stackbliz)暂不保存。 ### HMR -默认开启 HMR 功能,值为 none 时关闭。 +默认开启 HMR 功能,值为 `none` 时关闭。 ### HOST diff --git a/docs/docs/docs/guides/generator.md b/docs/docs/docs/guides/generator.md index 81a08ac981a9..b68878e074e2 100644 --- a/docs/docs/docs/guides/generator.md +++ b/docs/docs/docs/guides/generator.md @@ -4,7 +4,7 @@ toc: content --- # 微生成器 -Umi 中内置了众多微生成器,协助你在开发中快速的完成一些繁琐的工作。 +Umi 中内置了众多微生成器,协助你在开发中快速地完成一些繁琐的工作。 ## 如何使用 @@ -22,7 +22,7 @@ $ umi g ### 页面生成器 -快速生成一个新页面,有以下使用方式。 +快速生成一个新页面,有以下多种使用方式。 #### 基本使用 @@ -124,7 +124,7 @@ const count = 10 ##### 预设变量 -在上一小节生成的内容中,我们并没有指定 `name`,但它被还是设置值了。这是因为它属于模板中预设的变量,下面是目前页面模板所有的预设变量: +在上一小节生成的内容中,我们并没有指定 `name`,但它还是被设置为了一个值。这是因为它属于模板中预设的变量,下面是目前页面模板所有的预设变量: |参数|默认值|说明| |:-:|:-:|:-| @@ -203,7 +203,7 @@ Write: src/components/Orange/component.tsx #### 对组件模板内容进行自定义 -与[页面生成器](#对页面模板内容进行自定义)相同,组件生成器也支持对模板内容自定义。首先,先将原始模板写入到项目的 `/templates/component` 目录: +与[页面生成器](#对页面模板内容进行自定义)相同,组件生成器也支持对模板内容自定义。首先,将原始模板写入到项目的 `/templates/component` 目录: ```bash $umi g component --eject @@ -309,7 +309,7 @@ info - Write jest.config.ts ### Tailwind CSS 配置生成器 -为项目开启 [Tailwind CSS](https://tailwindcss.com/) 配置,命令执行后,`umi` 会生成 Tailwind CSS 和安装相应的的依赖。 +为项目开启 [Tailwind CSS](https://tailwindcss.com/) 配置,命令执行后,`umi` 会生成 Tailwind CSS 和安装相应的依赖。 ```bash $umi g tailwindcss @@ -323,7 +323,7 @@ info - Write tailwind.css ### DvaJS 配置生成器 -为项目开启 [Dva](https://dvajs.com/) 配置,命令执行后,`umi` 会生成 Dva +为项目开启 [Dva](https://dvajs.com/) 配置,命令执行后,`umi` 会生成 Dva 。 ```bash $umi g dva diff --git a/docs/docs/docs/guides/mock.md b/docs/docs/docs/guides/mock.md index 9d4e4259d734..3bc7002f676e 100644 --- a/docs/docs/docs/guides/mock.md +++ b/docs/docs/docs/guides/mock.md @@ -53,7 +53,7 @@ export default { ### 请求方法 -当 Http 的请求方法是 GET 时,可以省略方法部分,只需要路径即可,例如: +当 HTTP 的请求方法是 GET 时,可以省略方法部分,只需要路径即可,例如: ```ts // ./mock/users.ts @@ -140,7 +140,7 @@ MOCK=none umi dev ## 引入 Mock.js -在 Mock 中我们经常使用 [Mock.js](http://mockjs.com/) 来帮我们方便的生成随机的模拟数据,如果你使用了 Umi 的 Mock +在 Mock 中我们经常使用 [Mock.js](http://mockjs.com/) 来帮我们方便地生成随机的模拟数据。如果你使用了 Umi 的 Mock 功能,建议你搭配这个库来提升模拟数据的真实性: ```ts @@ -156,4 +156,4 @@ export default { ## 其他配置 -关于 Mock 功能完整的的其他配置项,请在文档的 [配置](../api/config#mock) 章节中查看。 +关于 Mock 功能完整的其他配置项,请在文档的 [配置](../api/config#mock) 章节中查看。 diff --git a/docs/docs/docs/guides/mpa.md b/docs/docs/docs/guides/mpa.md index dc4ac88f963e..da85a58ade2a 100644 --- a/docs/docs/docs/guides/mpa.md +++ b/docs/docs/docs/guides/mpa.md @@ -34,7 +34,7 @@ MPA 的目录结构是 `src/pages/${dir}/index.tsx` ,每个文件夹 `${dir}` ## 约定的入口文件 -默认的入口文件是 `src/pages` 目录下 `*/index.[jt]sx?` 文件。 +默认的入口文件是 `src/pages` 目录下的 `*/index.[jt]sx?` 文件。 比如: @@ -115,7 +115,7 @@ export const config = { ### 按需启动 -支持通过设置 `env.MPA_FILTER` 来指定需要启动的页面,以提高构建速度 +支持通过设置 `env.MPA_FILTER` 来指定需要启动的页面,以提高构建速度: ```text # file .env @@ -133,7 +133,7 @@ export default function Page() { } ``` -默认启用 React 18,如果需要 React 17 的渲染方式,请在项目中安装 react 17 的依赖,框架会自动适配 react 版本。 +默认启用 React 18,如果需要 React 17 的渲染方式,请在项目中安装 React 17 的依赖,框架会自动适配 React 版本。 ```bash $ pnpm i react@17 react-dom@17 diff --git a/docs/docs/docs/guides/plugins.md b/docs/docs/docs/guides/plugins.md index aa02ce3e2124..8b767334e6e8 100644 --- a/docs/docs/docs/guides/plugins.md +++ b/docs/docs/docs/guides/plugins.md @@ -3,7 +3,7 @@ order: 16 toc: content --- # 开发插件 -Umi 的核心就在于它的插件机制。基于 Umi 的插件机制,你可以获得扩展项目的编译时和运行时的能力。你可以利用我们提供的 [插件API](../api/plugin-api) 来自由编写插件,进而实现修改代码打包配置,修改启动代码,约定目录结构,修改 HTML 等丰富的功能。 +Umi 的核心就在于它的插件机制。基于 Umi 的插件机制,你可以获得扩展项目的编译时和运行时的能力。你可以利用我们提供的 [插件API](../api/plugin-api) 来自由地编写插件,进而实现修改代码打包配置、修改启动代码、约定目录结构、修改 HTML 等丰富的功能。 ## 核心概念 插件的本质就是一个方法,该方法接收了一个参数:api。在插件中,你可以调用 api 提供的方法进行一些 hook 的注册,随后 Umi 会在特定的时机执行这些 hook。 @@ -28,7 +28,7 @@ export default (api: IApi) => { }); }; ``` -这个插件的作用是根据用户配置的 changeFavicon 值来更改配置中的 favicons,(一个很简单且没有实际用途的例子XD)。可以看到插件其实就是一个接收了参数 api 的方法。在这个方法中,我们调用了 `api.modifyConfig` 注册了一个 hook: `(memo)=>{...}`。当你在配置中配置了 `changeFavicon` 之后, Umi 会注册该插件。在 Umi 收集配置的生命周期里,我们在插件里注册的 hook 将被执行,此时配置中的 `favicon` 就会被修改为用户配置中的 `changeFavicon` +这个插件的作用是根据用户配置的 changeFavicon 值来更改配置中的 favicons,(一个很简单且没有实际用途的例子XD)。可以看到插件其实就是一个接收了参数 api 的方法。在这个方法中,我们调用了 `api.modifyConfig` 注册了一个 hook: `(memo)=>{...}`。当你在配置中配置了 `changeFavicon` 之后, Umi 会注册该插件。在 Umi 收集配置的生命周期里,我们在插件里注册的 hook 将被执行,此时配置中的 `favicon` 就会被修改为用户配置中的 `changeFavicon` 。 ### plugin 和 preset preset 的作用是预设一些插件,它通常用来注册一批 presets 和 plugins。在 preset 中,上述提到的接受 api 的方法可以有返回值,该返回值是一个包含 plugins 和 presets 属性的对象,其作用就是注册相应的插件或者插件集。 @@ -44,7 +44,7 @@ export default (api: IApi) => { } }; ``` -它们的注册顺序是值得注意的: presets 始终先于 plugins 注册。Umi 维护了两个队列分别用来依次注册 presets 和 plugins,这个例子中的注册的 `preset_foo` 将被置于 presets 队列队首,而 `plugin_foo` 和 `plugin_bar` 将被依次置于 plugins 队列队尾。这里把 preset 放在队首的目的在于保证 presets 之间的顺序和关系是可控的。 +它们的注册顺序是值得注意的:presets 始终先于 plugins 注册。Umi 维护了两个队列分别用来依次注册 presets 和 plugins,这个例子中的注册的 `preset_foo` 将被置于 presets 队列队首,而 `plugin_foo` 和 `plugin_bar` 将被依次置于 plugins 队列队尾。这里把 preset 放在队首的目的在于保证 presets 之间的顺序和关系是可控的。 另外一个值得注意的点是:在 plugin 中,你也可以 return 一些 plugins 或者 presets,但是 Umi 不会对它做任何事情。 @@ -124,9 +124,9 @@ export default{ ### 插件 key 的默认命名规则 如果插件是一个包的话,key 的默认值将是去除前缀的包名。比如 `@umijs/plugin-foo` 的 key 默认为 `foo`, `@alipay/umi-plugin-bar` 的 key 默认为 `bar`。值得注意的是,该默认规则要求你的包名符合 Umi 插件的命名规范。 -如果插件不是一个包的话,key 的默认值将是插件的文件名。比如 `./plugins/foo.js` 的 key 默认为 `foo` +如果插件不是一个包的话,key 的默认值将是插件的文件名。比如 `./plugins/foo.js` 的 key 默认为 `foo` 。 -为了避免不必要的麻烦,我们建议你为自己编写的插件显示地声明其 key。 +为了避免不必要的麻烦,我们建议你为自己编写的插件显式地声明其 key。 ## Umi 插件的机制及其生命周期 @@ -140,7 +140,7 @@ export default{ - resolveConfig stage: 该阶段 Umi 将整理各个插件中对于 `config schema` 的定义,然后执行插件的 `modifyConfig` 、`modifyDefaultConfig`、 `modifyPaths` 等 hook,进行配置的收集。 - collectionAppData stage: 该阶段 Umi 执行 `modifyAppData` hook,来维护 App 的元数据。( `AppData` 是 `umi@4` 新增的 api ) - onCheck stage: 该阶段 Umi 执行 `onCheck` hook。 -- onStart stage: 该阶段 Umi 执行 `onStart` hook +- onStart stage: 该阶段 Umi 执行 `onStart` hook。 - runCommand stage: 该阶段 Umi 运行当前 cli 要执行的 command,(例如 `umi dev`, 这里就会执行 dev command)Umi 的各种核心功能都在 command 中实现。包括我们的插件调用 api 注册的绝大多数 hook。 以上就是 Umi 的插件机制的整体流程。 @@ -149,20 +149,20 @@ export default{ `register()` 接收一个 key 和 一个 hook,它维护了一个 `key-hook[]` 的 map,每当调用 `register()` 的时候,就会为 key 额外注册一个 hook。 -`register()` 注册的 hooks 供 applyPlugins 使用。 这些 hook 的执行顺序参照 [tapable](https://github.com/webpack/tapable) +`register()` 注册的 hooks 供 applyPlugins 使用。 这些 hook 的执行顺序参照 [tapable](https://github.com/webpack/tapable)。 -`registerMethod()` 接收一个 key 和 一个 fn,它会在 api 上注册一个方法。如果你没有向 `registerMethod()` 中传入 fn,那么 `registerMethod()` 会在 api 上注册一个"注册器": 它会将 `register()` 传入 key 并柯里化后的结果作为 fn 注册到 api 上。这样就可以通过调用这个"注册器",快捷地为 key 注册 hook 了。 +`registerMethod()` 接收一个 key 和 一个 fn,它会在 api 上注册一个方法。如果你没有向 `registerMethod()` 中传入 fn,那么 `registerMethod()` 会在 api 上注册一个“注册器”: 它会将 `register()` 传入 key 并柯里化后的结果作为 fn 注册到 api 上。这样就可以通过调用这个“注册器”,快捷地为 key 注册 hook 了。 -关于上述 api 的更具体的使用,请参照[插件 API](../api/plugin-api) +关于上述 api 的更具体的使用,请参照[插件 API](../api/plugin-api)。 ### PluginAPI 的原理 Umi 会为每个插件赋予一个 PluginAPI 对象,这个对象引用了插件本身和 Umi 的 service。 -Umi 为 PluginAPI 对象的 get() 方法进行了 proxy, 具体规则如下: +Umi 为 PluginAPI 对象的 `get()` 方法进行了 proxy,具体规则如下: - pluginMethod: 如果 prop 是 Umi 所维护的 `pluginMethods[]` ( `通过 registerMethod()` 注册的方法 )中的方法,则返回这个方法。 - service props: 如果 prop 是 serviceProps 数组中的属性(这些属性是 Umi 允许插件直接访问的属性),则返回 service 对应的属性。 - static props: 如果 prop 是参数 staticProps 数组中的属性(这些属性是静态变量,诸如一些类型定义和常量),则将其返回。 -- 否则返回 api 的属性 +- 否则返回 api 的属性。 因此,Umi 提供给插件的 api 绝大多数都是依靠 `registerMethod()` 来实现的,你可以直接使用我们的这些 api 快速地在插件中注册 hook。这也是 Umi 将框架和功能进行解耦的体现: Umi 的 service 只提供插件的管理功能,而 api 都依靠插件来提供。 @@ -170,6 +170,6 @@ Umi 为 PluginAPI 对象的 get() 方法进行了 proxy, 具体规则如下: `umi-core` 提供了一套插件的注册及管理机制。而 Umi 的核心功能都靠 [preset-umi](https://github.com/umijs/umi/tree/master/packages/preset-umi) 来实现。 `preset-umi` 其实就是内置的一个插件集,它提供的插件分为三大类: -- registerMethods 这类插件注册了一些上述提到的"注册器",以供开发者快速地注册 hook,这类方法也占据了 PluginAPI 中的大多数。 +- registerMethods 这类插件注册了一些上述提到的“注册器”,以供开发者快速地注册 hook,这类方法也占据了 PluginAPI 中的大多数。 - features 这类插件为 Umi 提供了一些特性,例如 appData、lowImport、mock 等。 - commands 这类插件注册了各类 command, 提供了 Umi CLI 的各种功能。Umi 能够在终端中正常运行,依靠的就是 command 提供的功能。 diff --git a/docs/docs/docs/guides/prepare.md b/docs/docs/docs/guides/prepare.md index fcdb06c080c0..b6af98c8bd89 100644 --- a/docs/docs/docs/guides/prepare.md +++ b/docs/docs/docs/guides/prepare.md @@ -16,7 +16,7 @@ Umi.js 需要使用 [Node.js](https://nodejs.org/zh-cn/) 来进行开发,因 Windows 用户建议使用 [nvm-windows](https://github.com/coreybutler/nvm-windows) 。 ::: -本文将以 macOS 或 Linux 环境下使用 [nvm](https://github.com/nvm-sh/nvm) 的方式安装 [Node.js](https://nodejs.org/zh-cn/) : +本文将在 macOS 或 Linux 环境下使用 [nvm](https://github.com/nvm-sh/nvm) 安装 [Node.js](https://nodejs.org/zh-cn/) : ```bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash @@ -58,7 +58,7 @@ pnpm -v ## IDE -安装完 [Node.js](https://nodejs.org/zh-cn/) 及 [pnpm](https://pnpm.io/) (或其他依赖管理工具) 后,你需要一个自己习惯的 IDE 或文本编辑器来编写代码。如果你还没有习惯的 IDE,可以从下方挑选一个: +安装完 [Node.js](https://nodejs.org/zh-cn/) 及 [pnpm](https://pnpm.io/) (或其他依赖管理工具) 后,你需要使用一个自己习惯的 IDE 或文本编辑器来编写代码。如果你还没有习惯的 IDE,可以从下方挑选一个: 1. [Visual Studio Code](https://code.visualstudio.com/) (推荐) 2. [WebStorm](https://www.jetbrains.com/webstorm/) (推荐) @@ -68,4 +68,4 @@ pnpm -v ## 下一步 -恭喜你!你的本地环境已经准备好开始开发 Umi.js 项目了,马上前往 [脚手架](boilerplate) 学习如何使用 Umi.js 脚手架快速启动一个项目吧 🎉 +恭喜你!你的本地环境已经准备好开始开发 Umi.js 项目了,马上前往 [脚手架](boilerplate) 学习如何使用 Umi.js 脚手架快速启动一个项目吧!🎉 diff --git a/docs/docs/docs/guides/proxy.md b/docs/docs/docs/guides/proxy.md index 47c713ca4b40..47b6e04c6b29 100644 --- a/docs/docs/docs/guides/proxy.md +++ b/docs/docs/docs/guides/proxy.md @@ -24,13 +24,13 @@ export default { 上述配置表示,将 `/api` 前缀的请求,代理到 `http://jsonplaceholder.typicode.com/`,替换请求地址中的 `/api` 为 `''`,并且将请求来源修改为目标url。如请求 `/api/a`,实际上是请求 `http://jsonplaceholder.typicode.com/a`。 -一般我们使用这个能力来解开发中的跨域访问问题。由于浏览器(或者 webview)存在同源策略,之前我们会让服务端配合使用 Cross-Origin Resource Sharing (CORS) 策略来绕过跨域访问问题。现在有了本地的 node 服务,我们就可以使用代理来解决这个问题。 +一般我们使用这个能力来解决开发中的跨域访问问题。由于浏览器(或者 webview)存在同源策略,之前我们会让服务端配合使用 Cross-Origin Resource Sharing (CORS) 策略来绕过跨域访问问题。现在有了本地的 node 服务,我们就可以使用代理来解决这个问题。 > XMLHttpRequest cannot load https://api.example.com. No 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 'http://localhost:8000' is therefore not allowed access. 原理其实很简单,就是浏览器上有跨域问题,但是服务端没有跨域问题。我们请求同源的本地服务,然后让本地服务去请求非同源的远程服务。需要注意的是,请求代理,代理的是请求的服务,不会直接修改发起的请求 url。它只是将目标服务器返回的数据传递到前端。所以你在浏览器上看到的请求地址还是 `http://localhost:8000/api/a`。 -值得注意的是 proxy 暂时只能解开发时(dev)的跨域访问问题,可以在部署时使用同源部署。如果在生产上(build)的发生跨域问题的话,可以将类似的配置转移到 Nginx 容器上。 +值得注意的是 proxy 暂时只能解开发时(dev)的跨域访问问题,可以在部署时使用同源部署。如果在生产上(build)发生跨域问题的话,可以将类似的配置转移到 Nginx 容器上。 diff --git a/docs/docs/docs/guides/routes.md b/docs/docs/docs/guides/routes.md index 33aab16c6e26..ed064d37330d 100644 --- a/docs/docs/docs/guides/routes.md +++ b/docs/docs/docs/guides/routes.md @@ -27,7 +27,7 @@ export default { } ``` -Umi 4 默认按页拆包,从而有更快的页面加载速度,由于加载过程是异步的,所以往往你需要编写 [`loading.tsx`](./directory-structure#loadingtsxjsx) 来给项目添加加载样式,提升体验。 +Umi 4 默认按页拆包,从而有更快的页面加载速度,由于加载过程是异步的,所以往往你需要编写 [`loading.tsx`](./directory-structure#loadingtsxjsx) 来给项目添加加载样式,提升用户体验。 :::info{title=💡} 你可以在 Chrome Devtools > 网络 Tab 中将网络设置成低速,然后切换路由查看加载组件是否生效。 @@ -62,7 +62,7 @@ Umi 4 默认按页拆包,从而有更快的页面加载速度,由于加载 * Type: `string` -配置 location 和 path 匹配后用于渲染的 React 组件路径。可以是绝对路径,也可以是相对路径,如果是相对路径,会从 `src/pages` 开始寻找。 +配置 location 和 path 匹配后用于渲染的 React 组件路径。可以是绝对路径,也可以是相对路径。如果是相对路径,会从 `src/pages` 开始寻找。 如果指向 `src` 目录的文件,可以用 `@`,比如 `component: '@/layouts/basic'`,推荐使用 `@` 组织路由文件位置。 @@ -361,7 +361,7 @@ export default function() { ] ``` -这样,如果访问 `/foo`,`/` 和 `/users` 都不能匹配,会 fallback 到 404 路由,通过 `src/pages/404.tsx` 进行渲染。 +这样,如果访问 `/foo`,则 `/` 和 `/users` 都不能匹配,于是会 fallback 到 404 路由,通过 `src/pages/404.tsx` 进行渲染。 > 404 只有约定式路由会自动生效,如果使用配置式路由,需要自行配置 404 的通配路由。 diff --git a/docs/docs/docs/guides/styling.md b/docs/docs/docs/guides/styling.md index e2fdd32322b1..2e9608b14872 100644 --- a/docs/docs/docs/guides/styling.md +++ b/docs/docs/docs/guides/styling.md @@ -5,7 +5,7 @@ toc: content # 样式 -本文介绍各种在 Umi 项目中使用样式的方式。 +本文介绍在 Umi 项目中使用样式的各种方式。 ## 使用 CSS 样式 @@ -57,7 +57,7 @@ export default function () { Umi 默认支持 LESS (推荐),SASS 和 SCSS 样式的导入,你可以直接按照引入 CSS 文件的方式引入并使用这些由 CSS 预处理器处理的样式。 :::info{title=💡} -在 Umi 中使用 Sass(Scss) 需要额外安装预处理依赖 如: `npm add -D sass` +在 Umi 中使用 SASS (SCSS) 需要额外安装预处理依赖 如: `npm add -D sass` ::: ```jsx @@ -90,7 +90,7 @@ export default function () { } ``` -Umi 也同时提供了对 `.styl` 和 `.stylus` 文件的内置支持。使用必须安装 `stylus` 相应的预处理器依赖, 其他用法用上面的列子 +Umi 也同时提供了对 `.styl` 和 `.stylus` 文件的内置支持。使用前必须安装 `stylus` 相应的预处理器依赖,其他用法用上面的例子 ```bash # .styl and .stylus diff --git a/docs/docs/docs/guides/test.md b/docs/docs/docs/guides/test.md index 859507effba9..52a622dfd39a 100644 --- a/docs/docs/docs/guides/test.md +++ b/docs/docs/docs/guides/test.md @@ -8,7 +8,7 @@ toc: content ## 配置 -使用 Umi 4 的微生成器快速的配置好 Jest [参考](./generator#jest-配置生成器), 如果你需要修改 jest 相关的配置,可以在 `jest.config.ts` 修改。 +使用 Umi 4 的微生成器快速地配置好 Jest [参考](./generator#jest-配置生成器),如果你需要修改 jest 相关的配置,可以在 `jest.config.ts` 修改。 umi 项目 @@ -53,7 +53,7 @@ export default async () => { 假设我们需要测试一个 utils 函数 `reverseApiData`, 它将 api 请求的结果 `data` 对象的 key 和 value 互换。 -我们推荐将测试文件被测模块放在同一级目录,这样可以方便查看测试文件以便理解模块的功能。 +我们推荐将测试文件和被测模块放在同一级目录,这样可以方便查看测试文件以便理解模块的功能。 ```txt . @@ -132,7 +132,7 @@ test('reverseApiData reverse simple object', async () => { }); ``` -让每个测试用例只关注一个功能点,可以让用例在重构的时候给我们更准确的反馈,改动破坏了什么功能。更多的用例请 [参考](https://github.com/umijs/umi/tree/master/examples/test-test/utils/reverseApiData.test.ts) +让每个测试用例只关注一个功能点,可以让用例在重构的时候给我们更准确的反馈,例如改动破坏了什么功能。更多的用例请参考 [代码](https://github.com/umijs/umi/tree/master/examples/test-test/utils/reverseApiData.test.ts)。 ## UI 测试 diff --git a/docs/docs/docs/guides/use-vue.md b/docs/docs/docs/guides/use-vue.md index 448784f625f0..2a08f363bb0f 100644 --- a/docs/docs/docs/guides/use-vue.md +++ b/docs/docs/docs/guides/use-vue.md @@ -5,7 +5,7 @@ toc: content # 使用 Vue -本文介绍如何在 Umi 使用 Vue , Umi Vue 大部分配置和 React 相同,这里只列出一些 Vue 独有的配置 +本文介绍如何在 Umi 中使用 Vue , Umi Vue 大部分配置和 React 相同,这里只列出一些 Vue 独有的配置。 ## 启动方式 @@ -30,14 +30,14 @@ export default { ### 配置式路由 :::info -这里仅列出和 React 路由配置差异部分 +这里仅列出和 React 路由配置差异部分。 ::: #### name 命名路由 -除了 `path` 之外,你还可以为任何路由提供 `name` +除了 `path` 之外,你还可以为任何路由提供 `name` : ```ts export default { @@ -51,7 +51,7 @@ export default { } ``` -要链接到一个命名的路由,可以向 `router-link` 组件的 to 属性传递一个对象: +要链接到一个命名的路由,可以向 `router-link` 组件的 `to` 属性传递一个对象: ```html @@ -168,7 +168,7 @@ const onHello = () => { ## 运行时配置 -可以通过在约定的 `src/app.tsx` 通过 export 配置来控制 vue vue-router 相关的配置 +可以通过在约定的 `src/app.tsx` 通过 export 配置来控制 vue vue-router 相关的配置。 ### router @@ -186,7 +186,7 @@ export const router: RouterConfig = { ### onMounted(\{app, router\}) -Vue app mount 成功回调, 这里可以拿到 app 的实例及 router 的实例, 可以进行全局组件注册, 路由拦截器等。 +Vue app mount 成功回调,这里可以拿到 app 的实例及 router 的实例,可以进行全局组件注册,路由拦截器等。 ```ts export function onMounted({ app, router }: any) { @@ -212,9 +212,9 @@ export function rootContainer(container) { } ``` -## examples +## Examples -更多详见 demo +更多详见 demo : * [boilerplate-vue](https://github.com/umijs/umi/tree/master/examples/boilerplate-vue) * [with-vue-pinia](https://github.com/umijs/umi/tree/master/examples/with-vue-pinia) diff --git a/docs/docs/docs/introduce/introduce.md b/docs/docs/docs/introduce/introduce.md index 800eef9f3fce..916a111a8b02 100644 --- a/docs/docs/docs/introduce/introduce.md +++ b/docs/docs/docs/introduce/introduce.md @@ -9,7 +9,7 @@ toc: content ## Umi 是什么? -Umi,中文发音为「乌米」,是可扩展的企业级前端应用框架。Umi 以路由为基础的,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求。 +Umi,中文发音为「乌米」,是可扩展的企业级前端应用框架。Umi 以路由为基础,同时支持配置式路由和约定式路由,保证路由的功能完备,并以此进行功能扩展。然后配以生命周期完善的插件体系,覆盖从源码到构建产物的每个生命周期,支持各种功能扩展和业务需求。 Umi 是蚂蚁集团的底层前端框架,已直接或间接地服务了 10000+ 应用,包括 Java、Node、H5 无线、离线(Hybrid)应用、纯前端 assets 应用、CMS 应用、Electron 应用、Serverless 应用等。他已经很好地服务了我们的内部用户,同时也服务了不少外部用户,包括淘系、飞猪、阿里云、字节、腾讯、口碑、美团等。在 2021 年字节的[调研报告](https://zhuanlan.zhihu.com/p/403206195)中,Umi 是其中 25.33% 开发者的选择。 @@ -49,7 +49,7 @@ create-react-app 是脚手架,和 Umi、next.js、remix、ice、modern.js 等 ### next.js -如果要做 SSR,next.js 是非常好的选择(当然,Umi 也支持 SSR);而如果只做 CSR,Umi 会是更好的选择。相比之下,Umi 的扩展性会更好;并且 Umi 做了很多更贴地气的功能,比如配置式路由、补丁方案、antd 的接入、微前端、国际化、权限等;同时 Umi 会更稳定,因为他锁了能锁的全部依赖,定期主动更新,某一个子版本的 Umi,不会因为重装依赖之后而跑不起来。 +如果要做 SSR,next.js 是非常好的选择(当然,Umi 也支持 SSR);而如果只做 CSR,Umi 会是更好的选择。相比之下,Umi 的扩展性会更好;并且 Umi 做了很多更贴地气的功能,比如配置式路由、补丁方案、antd 的接入、微前端、国际化、权限等;同时 Umi 会更稳定,因为他锁了能锁的全部依赖,定期主动更新。某一个子版本的 Umi,不会因为重装依赖之后而跑不起来。 ### remix diff --git a/docs/docs/docs/introduce/philosophy.md b/docs/docs/docs/introduce/philosophy.md index 32f39b67644f..0fc950eed242 100644 --- a/docs/docs/docs/introduce/philosophy.md +++ b/docs/docs/docs/introduce/philosophy.md @@ -54,7 +54,7 @@ Umi 通过写死版本、依赖预打包、通过 eslint hack 锁定 eslint 依 ## import all from umi -很多人可能都第一次听到。import all from umi 意思是所有 import 都来自 `umi`。比如 dva 不是 `import { connect } from 'dva'`,而是 `import { connect } from 'umi'`,从 umi 中导出。导出的方法不仅来自 umi 自身,还来自 umi 插件。 +很多人可能都第一次听到。import all from umi 意思是所有 import 都来自 `umi`。比如 dva 不是 `import { connect } from 'dva'`,而是 `import { connect } from 'umi'`,从 Umi 中导出。导出的方法不仅来自 Umi 自身,还来自 Umi 插件。 这是两年前 Umi 3 加的功能,最近发现 Remix、prisma、vitekit 等框架和工具都有类似实现。 diff --git a/docs/docs/docs/introduce/upgrade-to-umi-4.md b/docs/docs/docs/introduce/upgrade-to-umi-4.md index 2680d91e93fb..77112efa8aed 100644 --- a/docs/docs/docs/introduce/upgrade-to-umi-4.md +++ b/docs/docs/docs/introduce/upgrade-to-umi-4.md @@ -34,7 +34,7 @@ toc: content ### 启动命令 -如果使用了 `@umijs/max` 可以使用 `max` 命令来替换 `umi`,`max dev`,`max build` 等 +如果使用了 `@umijs/max` 可以使用 `max` 命令来替换 `umi`,`max dev`,`max build` 等。 `umi@4` 将一些项目前置操作放到了 `setup` 命令中,如 umi@3 中的 `umi g tmp` 等命令,需要使用 `umi setup` 替换 From 9ff52dbbefd0d9a560fac20b53b096a7059e8d60 Mon Sep 17 00:00:00 2001 From: Jeff Tian Date: Tue, 7 Nov 2023 05:34:05 +0800 Subject: [PATCH 08/19] docs(fix): change ; to , to avoid errors (#11781) I copied and pasted the configs and found errors. Trying to fix it. --- docs/docs/docs/api/config.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/docs/api/config.md b/docs/docs/docs/api/config.md index 4d3965b4e430..5cb7d530f140 100644 --- a/docs/docs/docs/api/config.md +++ b/docs/docs/docs/api/config.md @@ -1450,7 +1450,7 @@ import SmileUrl, { ReactComponent as SvgSmile } from './smile.svg'; ```js // 兼容 ie11 targets: { - ie: 11; + ie: 11, } ``` From af457bc0b2f81143a62867be72271fb2ed0b82d7 Mon Sep 17 00:00:00 2001 From: lijianan <574980606@qq.com> Date: Tue, 7 Nov 2023 05:42:28 +0800 Subject: [PATCH 09/19] chore: update dva examples (#11789) * chore: update dva examples * chore: update lock * Update package.json --- examples/max/package.json | 1 + examples/max/pages/dva.tsx | 3 +-- pnpm-lock.yaml | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/max/package.json b/examples/max/package.json index ed643b96d75b..4b98d5bd03ba 100644 --- a/examples/max/package.json +++ b/examples/max/package.json @@ -18,6 +18,7 @@ "@ant-design/icons": "^4.7.0", "@umijs/max": "workspace:*", "antd": "^4.23.2", + "dayjs": "^1.11.7", "react": "18.1.0", "react-dom": "18.1.0" }, diff --git a/examples/max/pages/dva.tsx b/examples/max/pages/dva.tsx index a8378537b1d7..9a5e9b7509c4 100644 --- a/examples/max/pages/dva.tsx +++ b/examples/max/pages/dva.tsx @@ -1,7 +1,6 @@ // @ts-ignore import { connect } from '@@/plugin-dva'; -// @ts-ignore -import dayjs from 'moment'; +import dayjs from 'dayjs'; function mapStateToProps(state: any) { return { count: state.count }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index dbedd726a38c..5eb8197e6e17 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -738,6 +738,9 @@ importers: antd: specifier: ^4.23.2 version: 4.23.2(react-dom@18.1.0)(react@18.1.0) + dayjs: + specifier: ^1.11.7 + version: 1.11.7 react: specifier: 18.1.0 version: 18.1.0 From 48b5d3c77f36d77d6c0115cccd4ef6131b21324e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=92=B2=E5=A5=88Sakina?= <59400654+fz6m@users.noreply.github.com> Date: Tue, 7 Nov 2023 05:48:12 +0800 Subject: [PATCH 10/19] feat: add ssr types and refactor some logic (#11784) * refactor: PR #11755 comment * feat: export serverLoader types * example: serverLoader case * feat: add `useServerLoaderData` type * refactor: PR #11724 comment --- examples/ssr-demo/src/pages/index.tsx | 9 ++-- examples/ssr-demo/tsconfig.json | 3 ++ packages/preset-umi/src/features/ssr/ssr.ts | 17 +++++- .../src/features/ssr/webpack/webpack.ts | 6 ++- packages/renderer-react/src/appContext.ts | 7 ++- packages/renderer-react/src/browser.tsx | 9 +++- packages/server/src/ssr.ts | 54 ++++++++++++------- packages/server/src/types.ts | 9 ++++ 8 files changed, 82 insertions(+), 32 deletions(-) create mode 100644 examples/ssr-demo/tsconfig.json diff --git a/examples/ssr-demo/src/pages/index.tsx b/examples/ssr-demo/src/pages/index.tsx index 1c1efec02c6d..e5b750b5354c 100644 --- a/examples/ssr-demo/src/pages/index.tsx +++ b/examples/ssr-demo/src/pages/index.tsx @@ -1,5 +1,5 @@ -import React from 'react'; import { + IServerLoaderArgs, Link, useClientLoaderData, useServerInsertedHTML, @@ -18,7 +18,7 @@ import umiLogo from './umi.png'; export default function HomePage() { const clientLoaderData = useClientLoaderData(); - const serverLoaderData = useServerLoaderData(); + const serverLoaderData = useServerLoaderData(); useServerInsertedHTML(() => { return
inserted html
; @@ -51,7 +51,8 @@ export async function clientLoader() { return { message: 'data from client loader of index.tsx' }; } -export async function serverLoader() { +export async function serverLoader({ request }: IServerLoaderArgs) { + const { url } = request; await new Promise((resolve) => setTimeout(resolve, Math.random() * 1000)); - return { message: 'data from server loader of index.tsx' }; + return { message: `data from server loader of index.tsx, url: ${url}` }; } diff --git a/examples/ssr-demo/tsconfig.json b/examples/ssr-demo/tsconfig.json new file mode 100644 index 000000000000..133cfd82a23f --- /dev/null +++ b/examples/ssr-demo/tsconfig.json @@ -0,0 +1,3 @@ +{ + "extends": "./src/.umi/tsconfig.json" +} diff --git a/packages/preset-umi/src/features/ssr/ssr.ts b/packages/preset-umi/src/features/ssr/ssr.ts index 2136eb37006b..ec65e3c5971e 100644 --- a/packages/preset-umi/src/features/ssr/ssr.ts +++ b/packages/preset-umi/src/features/ssr/ssr.ts @@ -3,10 +3,10 @@ import type { Compiler, } from '@umijs/bundler-webpack/compiled/webpack'; import { EnableBy } from '@umijs/core/dist/types'; -import { fsExtra, importLazy, logger } from '@umijs/utils'; +import { fsExtra, importLazy, logger, winPath } from '@umijs/utils'; import assert from 'assert'; import { existsSync, writeFileSync } from 'fs'; -import { join } from 'path'; +import { dirname, join } from 'path'; import type { IApi } from '../../types'; import { absServerBuildPath } from './utils'; @@ -61,6 +61,11 @@ export default (api: IApi) => { }, ]); + const serverPackagePath = dirname( + require.resolve('@umijs/server/package.json'), + ); + const ssrTypesPath = join(serverPackagePath, './dist/types'); + api.onGenerateFiles(() => { // react-shim.js is for esbuild to build umi.server.js api.writeTmpFile({ @@ -93,6 +98,14 @@ export function useServerInsertedHTML(callback: () => React.ReactNode): void { addInsertedServerHTMLCallback(callback); } } +`, + }); + + // types + api.writeTmpFile({ + path: 'types.d.ts', + content: ` +export type { IServerLoaderArgs, UmiRequest } from '${winPath(ssrTypesPath)}' `, }); }); diff --git a/packages/preset-umi/src/features/ssr/webpack/webpack.ts b/packages/preset-umi/src/features/ssr/webpack/webpack.ts index 687caf4fbec3..e4a18c190be9 100644 --- a/packages/preset-umi/src/features/ssr/webpack/webpack.ts +++ b/packages/preset-umi/src/features/ssr/webpack/webpack.ts @@ -1,10 +1,10 @@ import * as bundlerWebpack from '@umijs/bundler-webpack'; import type WebpackChain from '@umijs/bundler-webpack/compiled/webpack-5-chain'; +import { Env } from '@umijs/bundler-webpack/dist/types'; import { lodash, logger } from '@umijs/utils'; import { dirname, resolve } from 'path'; import { IApi } from '../../../types'; import { absServerBuildPath } from '../utils'; -import { Env } from "@umijs/bundler-webpack/dist/types"; export const build = async (api: IApi, opts: any) => { logger.wait('[SSR] Compiling...'); @@ -47,7 +47,9 @@ export const build = async (api: IApi, opts: any) => { memo.output .path(dirname(absOutputFile)) // 避免多 chunk 时的命名冲突,虽然 ssr 在项目里禁用了 import() 语法,但 node_modules 下可能存在的 import() 没有被 babel 插件覆盖到 - .filename(useHash ? '[name].[contenthash:8].server.js' : '[name].server.js') + .filename( + useHash ? '[name].[contenthash:8].server.js' : '[name].server.js', + ) .chunkFilename( useHash ? '[name].[contenthash:8].server.js' : '[name].server.js', ) diff --git a/packages/renderer-react/src/appContext.ts b/packages/renderer-react/src/appContext.ts index bf6a79c59ddf..dc7ba72bff54 100644 --- a/packages/renderer-react/src/appContext.ts +++ b/packages/renderer-react/src/appContext.ts @@ -43,10 +43,13 @@ export function useRouteProps = any>() { return props as T; } -export function useServerLoaderData() { +type ServerLoaderFunc = (...args: any[]) => Promise | any; +export function useServerLoaderData() { const route = useRouteData(); const appData = useAppData(); - return { data: appData.serverLoaderData[route.route.id] }; + return { + data: appData.serverLoaderData[route.route.id] as Awaited>, + }; } export function useClientLoaderData() { diff --git a/packages/renderer-react/src/browser.tsx b/packages/renderer-react/src/browser.tsx index 9d36283bfd43..4ad527a96edc 100644 --- a/packages/renderer-react/src/browser.tsx +++ b/packages/renderer-react/src/browser.tsx @@ -266,8 +266,9 @@ const getBrowser = ( // use ?. since routes patched with patchClientRoutes is not exists in opts.routes if (!isFirst && opts.routes[id]?.hasServerLoader) { // 在有basename的情况下__serverLoader的请求路径需要加上basename - fetch((basename.endsWith('/') ? basename : basename + '/') + '__serverLoader?route=' + id, { - credentials: 'include' + const url = `${withEndSlash(basename)}'__serverLoader?route='${id}`; + fetch(url, { + credentials: 'include', }) .then((d) => d.json()) .then((data) => { @@ -350,3 +351,7 @@ export function renderClient(opts: RenderClientOpts) { // @ts-ignore ReactDOM.render(, rootElement); } + +function withEndSlash(str: string) { + return str.endsWith('/') ? str : `${str}/`; +} diff --git a/packages/server/src/ssr.ts b/packages/server/src/ssr.ts index 56398612bdcd..a254026b3b9c 100644 --- a/packages/server/src/ssr.ts +++ b/packages/server/src/ssr.ts @@ -2,7 +2,7 @@ import React, { ReactElement } from 'react'; import * as ReactDomServer from 'react-dom/server'; import { matchRoutes } from 'react-router-dom'; import { Writable } from 'stream'; -import type { IRoutesById } from './types'; +import type { IRoutesById, IServerLoaderArgs, UmiRequest } from './types'; interface RouteLoaders { [key: string]: () => Promise; @@ -10,12 +10,19 @@ interface RouteLoaders { export type ServerInsertedHTMLHook = (callbacks: () => React.ReactNode) => void; -// serverLoader的参数类型 -export interface IServerLoaderArgs { - request: Request; +interface CreateRequestServerlessOptions { + /** + * only return body html + * @example
{app}
... + */ + withoutHTML?: boolean; + /** + * folder path for `build-manifest.json` + */ + sourceDir?: string; } -interface CreateRequestHandlerOptions { +interface CreateRequestHandlerOptions extends CreateRequestServerlessOptions { routesWithServerLoader: RouteLoaders; PluginManager: any; manifest: @@ -28,8 +35,6 @@ interface CreateRequestHandlerOptions { createHistory: (opts: any) => any; helmetContext?: any; ServerInsertedHTMLContext: React.Context; - withoutHTML?: boolean; - sourceDir?: string; } const createJSXProvider = ( @@ -214,21 +219,22 @@ export default function createRequestHandler( return async function (req: any, res: any, next: any) { // 切换路由场景下,会通过此 API 执行 server loader if (req.url.startsWith('/__serverLoader') && req.query.route) { + const loaderArgs: IServerLoaderArgs = { + request: req, + }; const data = await executeLoader( req.query.route, opts.routesWithServerLoader, - { request: req }, + loaderArgs, ); res.status(200).json(data); return; } - const request = new Request( - req.protocol + '://' + req.get('host') + req.originalUrl, - { - headers: req.headers, - }, - ); + const fullUrl = `${req.protocol}://${req.get('host')}${req.originalUrl}`; + const request = new Request(fullUrl, { + headers: req.headers, + }); const jsx = await jsxGeneratorDeferrer(req.url, { request }); if (!jsx) return next(); @@ -259,14 +265,21 @@ export default function createRequestHandler( // 新增的给CDN worker用的SSR请求handle export function createUmiHandler(opts: CreateRequestHandlerOptions) { - return async function (req: Request, params?: CreateRequestHandlerOptions) { + return async function ( + req: UmiRequest, + params?: CreateRequestHandlerOptions, + ) { const jsxGeneratorDeferrer = createJSXGenerator({ ...opts, ...params, }); - const jsx = await jsxGeneratorDeferrer(new URL(req.url).pathname, { + const loaderArgs: IServerLoaderArgs = { request: req, - }); + }; + const jsx = await jsxGeneratorDeferrer( + new URL(req.url).pathname, + loaderArgs, + ); if (!jsx) { throw new Error('no page resource'); @@ -277,12 +290,13 @@ export function createUmiHandler(opts: CreateRequestHandlerOptions) { } export function createUmiServerLoader(opts: CreateRequestHandlerOptions) { - return async function (req: Request) { + return async function (req: UmiRequest) { const query = Object.fromEntries(new URL(req.url).searchParams); // 切换路由场景下,会通过此 API 执行 server loader - return await executeLoader(query.route, opts.routesWithServerLoader, { + const loaderArgs: IServerLoaderArgs = { request: req, - }); + }; + return executeLoader(query.route, opts.routesWithServerLoader, loaderArgs); }; } diff --git a/packages/server/src/types.ts b/packages/server/src/types.ts index f8b498ab6226..8726ab7dd271 100644 --- a/packages/server/src/types.ts +++ b/packages/server/src/types.ts @@ -12,3 +12,12 @@ export interface IRoutesById { export interface IRouteCustom extends IRoute { [key: string]: any; } + +export type UmiRequest = Partial & Pick; + +/** + * serverLoader 的参数类型 + */ +export interface IServerLoaderArgs { + request: UmiRequest; +} From 4a93ea2b20f6c44a6ac470a5011ff3792894c5b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=BA=A2?= Date: Tue, 7 Nov 2023 05:59:03 +0800 Subject: [PATCH 11/19] fix(antd-plugin): fix console deprecation warning (#11630) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor(antd-plugin): move type.d.ts to tpl * fix: abandonment alerts due to misuse * chore: update tpl * chore: rename Co-authored-by: MadCcc * chore: remove extra diff * Update packages/plugins/src/antd.ts --------- Co-authored-by: MadCcc Co-authored-by: 咲奈Sakina <59400654+fz6m@users.noreply.github.com> --- packages/plugins/src/antd.ts | 39 +++++++------------ .../plugins/templates/antd/runtime.ts.tpl | 14 ++++++- .../plugins/templates/antd/types.d.ts.tpl | 17 ++++++++ 3 files changed, 43 insertions(+), 27 deletions(-) create mode 100644 packages/plugins/templates/antd/types.d.ts.tpl diff --git a/packages/plugins/src/antd.ts b/packages/plugins/src/antd.ts index 1f26a70aebd4..e7cf1ceece29 100644 --- a/packages/plugins/src/antd.ts +++ b/packages/plugins/src/antd.ts @@ -3,7 +3,7 @@ import AntdMomentWebpackPlugin from '@ant-design/moment-webpack-plugin'; import assert from 'assert'; import { dirname, join } from 'path'; import { IApi, RUNTIME_TYPE_FILE_NAME } from 'umi'; -import { deepmerge, Mustache, semver, winPath } from 'umi/plugin-utils'; +import { deepmerge, semver, winPath } from 'umi/plugin-utils'; import { TEMPLATES_DIR } from './constants'; import { resolveProjectDep } from './utils/resolveProjectDep'; import { withTmpPath } from './utils/withTmpPath'; @@ -255,37 +255,24 @@ export default (api: IApi) => { isV5 && (userInputCompact || userInputDark) ? { compact: userInputCompact, dark: userInputDark } : false, + /** + * 是否重构了全局静态配置。 重构后需要在运行时将全局静态配置传入到 ConfigProvider 中。 + * 实际上 4.13.0 重构后有一个 bug,真正的 warn 出现在 4.13.1,并且 4.13.1 修复了这个 bug。 + * Resolve issue: https://github.com/umijs/umi/issues/10231 + * `InternalStatic` 指 `Modal.config` 等静态方法,详见:https://github.com/ant-design/ant-design/pull/29285 + */ + disableInternalStatic: semver.gt(antdVersion, '4.13.0'), }, tplPath: winPath(join(ANTD_TEMPLATES_DIR, 'runtime.ts.tpl')), }); api.writeTmpFile({ path: 'types.d.ts', - content: Mustache.render( - ` -{{#withConfigProvider}} -import type { ConfigProviderProps } from 'antd/es/config-provider'; -{{/withConfigProvider}} -{{#withAppConfig}} -import type { AppConfig } from 'antd/es/app/context'; -{{/withAppConfig}} - -type Prettify = { - [K in keyof T]: T[K]; -} & {}; - -type AntdConfig = Prettify<{} -{{#withConfigProvider}} & ConfigProviderProps{{/withConfigProvider}} -{{#withAppConfig}} & { appConfig: AppConfig }{{/withAppConfig}} ->; - -export type RuntimeAntdConfig = (memo: AntdConfig) => AntdConfig; -`.trim(), - { - withConfigProvider, - withAppConfig, - }, - ), + context: { + withConfigProvider, + withAppConfig, + }, + tplPath: winPath(join(ANTD_TEMPLATES_DIR, 'types.d.ts.tpl')), }); api.writeTmpFile({ diff --git a/packages/plugins/templates/antd/runtime.ts.tpl b/packages/plugins/templates/antd/runtime.ts.tpl index 64b475e224bb..9a7d04a69649 100644 --- a/packages/plugins/templates/antd/runtime.ts.tpl +++ b/packages/plugins/templates/antd/runtime.ts.tpl @@ -1,12 +1,14 @@ import React from 'react'; import { - Modal, ConfigProvider, {{#appConfig}} App, {{/appConfig}} +{{^disableInternalStatic}} + Modal, message, notification, +{{/disableInternalStatic}} {{#enableV5ThemeAlgorithm}} theme, {{/enableV5ThemeAlgorithm}} @@ -50,6 +52,7 @@ export function rootContainer(rawContainer) { let container = rawContainer; {{#configProvider}} + {{^disableInternalStatic}} if (finalConfigProvider.prefixCls) { Modal.config({ rootPrefixCls: finalConfigProvider.prefixCls @@ -61,6 +64,15 @@ export function rootContainer(rawContainer) { prefixCls: `${finalConfigProvider.prefixCls}-notification` }); } + {{/disableInternalStatic}} + + {{#disableInternalStatic}} + if (finalConfigProvider.prefixCls) { + ConfigProvider.config({ + prefixCls: finalConfigProvider.prefixCls, + }); + }; + {{/disableInternalStatic}} if (finalConfigProvider.iconPrefixCls) { // Icons in message need to set iconPrefixCls via ConfigProvider.config() diff --git a/packages/plugins/templates/antd/types.d.ts.tpl b/packages/plugins/templates/antd/types.d.ts.tpl new file mode 100644 index 000000000000..029486da5564 --- /dev/null +++ b/packages/plugins/templates/antd/types.d.ts.tpl @@ -0,0 +1,17 @@ +{{#withConfigProvider}} +import type { ConfigProviderProps } from 'antd/es/config-provider'; +{{/withConfigProvider}} +{{#withAppConfig}} +import type { AppConfig } from 'antd/es/app/context'; +{{/withAppConfig}} + +type Prettify = { + [K in keyof T]: T[K]; +} & {}; + +type AntdConfig = Prettify<{} +{{#withConfigProvider}} & ConfigProviderProps{{/withConfigProvider}} +{{#withAppConfig}} & { appConfig: AppConfig }{{/withAppConfig}} +>; + +export type RuntimeAntdConfig = (memo: AntdConfig) => AntdConfig; From 56313d47c0d60d5fe124e0a04bdcba1135d33b78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=92=B2=E5=A5=88Sakina?= <59400654+fz6m@users.noreply.github.com> Date: Tue, 7 Nov 2023 06:10:26 +0800 Subject: [PATCH 12/19] chore: code format (#11837) --- examples/with-stylus/pages/index.tsx | 1 - packages/bundler-utils/src/proxy.ts | 4 ++-- packages/bundler-webpack/src/schema.ts | 6 +----- packages/plugins/src/mf.ts | 7 ++++--- packages/plugins/src/qiankun/slave.ts | 5 ++++- packages/renderer-react/src/server.tsx | 22 ++++++++++++---------- 6 files changed, 23 insertions(+), 22 deletions(-) diff --git a/examples/with-stylus/pages/index.tsx b/examples/with-stylus/pages/index.tsx index ae206b3efdf2..ecd65dedb040 100644 --- a/examples/with-stylus/pages/index.tsx +++ b/examples/with-stylus/pages/index.tsx @@ -1,4 +1,3 @@ -import React from 'react'; import './index.styl'; import styles from './index.styl'; diff --git a/packages/bundler-utils/src/proxy.ts b/packages/bundler-utils/src/proxy.ts index b7dafa8c146a..20fe9bb453d9 100644 --- a/packages/bundler-utils/src/proxy.ts +++ b/packages/bundler-utils/src/proxy.ts @@ -1,7 +1,7 @@ -import type { ProxyOptions } from './types'; +import assert from 'assert'; import type { Express } from '../compiled/express'; import { createProxyMiddleware } from '../compiled/http-proxy-middleware'; -import assert from 'assert'; +import type { ProxyOptions } from './types'; export function createProxy( proxy: { [key: string]: ProxyOptions } | ProxyOptions[], diff --git a/packages/bundler-webpack/src/schema.ts b/packages/bundler-webpack/src/schema.ts index 851828d26280..e9f9c7542db9 100644 --- a/packages/bundler-webpack/src/schema.ts +++ b/packages/bundler-webpack/src/schema.ts @@ -163,11 +163,7 @@ export function getSchemas(): Record any> { runtimePublicPath: ({ zod }) => zod.object({}), sassLoader: ({ zod }) => zod.record(zod.string(), zod.any()), srcTranspiler: ({ zod }) => - zod.enum([ - Transpiler.babel, - Transpiler.esbuild, - Transpiler.swc, - ]), + zod.enum([Transpiler.babel, Transpiler.esbuild, Transpiler.swc]), srcTranspilerOptions: ({ zod }) => zod .object({ diff --git a/packages/plugins/src/mf.ts b/packages/plugins/src/mf.ts index d0093827a0db..209726f84524 100644 --- a/packages/plugins/src/mf.ts +++ b/packages/plugins/src/mf.ts @@ -71,9 +71,10 @@ export default function mf(api: IApi) { ); } - const useHash = typeof api.config.mf.remoteHash === 'boolean' - ? api.config.mf.remoteHash - : (api.config.hash && api.env !== 'development'); + const useHash = + typeof api.config.mf.remoteHash === 'boolean' + ? api.config.mf.remoteHash + : api.config.hash && api.env !== 'development'; const mfConfig = { name, diff --git a/packages/plugins/src/qiankun/slave.ts b/packages/plugins/src/qiankun/slave.ts index a9dea5ff1b8d..2e976c28149b 100644 --- a/packages/plugins/src/qiankun/slave.ts +++ b/packages/plugins/src/qiankun/slave.ts @@ -185,7 +185,10 @@ export interface IRuntimeConfig { // 默认不修改 library chunk 的 name,从而确保可以通过 window[appName] 访问到导出 // mfsu 关闭的时候才可以修改,否则可能导致配合 mfsu 时,子应用的 umd chunk 无法被正确加载 // mfsu 线上不会开启,所以这里只需要判断本地是否开启即可 - const { shouldNotAddLibraryChunkName = api.env === 'production' || !Boolean(api.config.mfsu) } = (api.config.qiankun || {}).slave!; + const { + shouldNotAddLibraryChunkName = api.env === 'production' || + !Boolean(api.config.mfsu), + } = (api.config.qiankun || {}).slave!; config.output .libraryTarget('umd') .library( diff --git a/packages/renderer-react/src/server.tsx b/packages/renderer-react/src/server.tsx index 97e1fed31081..9414745d7f08 100644 --- a/packages/renderer-react/src/server.tsx +++ b/packages/renderer-react/src/server.tsx @@ -58,16 +58,18 @@ export async function getClientRootComponent(opts: { ); if (opts.withoutHTML) { - return <> -
{app}
-