From 886c4de8af05668be613ede0488d0e76ebadcb60 Mon Sep 17 00:00:00 2001 From: Linbudu <48507806+linbudu599@users.noreply.github.com> Date: Mon, 11 Mar 2024 11:18:44 +0800 Subject: [PATCH 01/10] fix(rax-compat): fix createElement (#6814) --- .changeset/famous-roses-hide.md | 5 +++++ packages/rax-compat/package.json | 3 ++- packages/rax-compat/src/runtime/index.ts | 1 + 3 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 .changeset/famous-roses-hide.md create mode 100644 packages/rax-compat/src/runtime/index.ts diff --git a/.changeset/famous-roses-hide.md b/.changeset/famous-roses-hide.md new file mode 100644 index 0000000000..424e5c83a0 --- /dev/null +++ b/.changeset/famous-roses-hide.md @@ -0,0 +1,5 @@ +--- +'rax-compat': patch +--- + +fix createElement runtime import diff --git a/packages/rax-compat/package.json b/packages/rax-compat/package.json index e80e5379bc..640189c8c3 100644 --- a/packages/rax-compat/package.json +++ b/packages/rax-compat/package.json @@ -22,6 +22,7 @@ "./find-dom-node": "./esm/find-dom-node.js", "./is-valid-element": "./esm/is-valid-element.js", "./unmount-component-at-node": "./esm/unmount-component-at-node.js", + "./runtime": "./esm/runtime/index.js", "./runtime/jsx-dev-runtime": "./esm/runtime/jsx-dev-runtime.js", "./runtime/jsx-runtime": "./esm/runtime/jsx-runtime.js", "./es2017": "./es2017/index.js" @@ -76,4 +77,4 @@ "author": "ice-admin@alibaba-inc.com", "license": "MIT", "homepage": "https://github.com/alibaba/ice#readme" -} +} \ No newline at end of file diff --git a/packages/rax-compat/src/runtime/index.ts b/packages/rax-compat/src/runtime/index.ts new file mode 100644 index 0000000000..5ad873a75f --- /dev/null +++ b/packages/rax-compat/src/runtime/index.ts @@ -0,0 +1 @@ +export { createElement } from '../create-element.js'; From ba811d72d3efc452c570528ba887b5d7c082851d Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Mon, 11 Mar 2024 16:06:14 +0800 Subject: [PATCH 02/10] Feat: support props for KeepAliveOutlet (#6819) * feat: support props for KeepAliveOutlet * fix: lint warning * fix: lint --- .changeset/brave-items-cover.md | 5 ++++ examples/with-keep-alive/src/pages/layout.tsx | 2 +- packages/runtime/src/KeepAliveOutlet.tsx | 23 +++++++++++++++---- 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100644 .changeset/brave-items-cover.md diff --git a/.changeset/brave-items-cover.md b/.changeset/brave-items-cover.md new file mode 100644 index 0000000000..ad1de7aa9f --- /dev/null +++ b/.changeset/brave-items-cover.md @@ -0,0 +1,5 @@ +--- +'@ice/runtime': patch +--- + +feat: support props for KeepAliveOutlet diff --git a/examples/with-keep-alive/src/pages/layout.tsx b/examples/with-keep-alive/src/pages/layout.tsx index c50545a199..cef958ddfc 100644 --- a/examples/with-keep-alive/src/pages/layout.tsx +++ b/examples/with-keep-alive/src/pages/layout.tsx @@ -4,7 +4,7 @@ export default function Layout() { return (

Layout

- +
); } diff --git a/packages/runtime/src/KeepAliveOutlet.tsx b/packages/runtime/src/KeepAliveOutlet.tsx index d300e5b977..8c4a667f83 100644 --- a/packages/runtime/src/KeepAliveOutlet.tsx +++ b/packages/runtime/src/KeepAliveOutlet.tsx @@ -10,41 +10,54 @@ interface ActivityItem { pathname: string; } -export default function KeepAliveOutlet() { +interface OutletProps { + // The limitation number of outlets to keep alive. + limit?: number; + // When paths is configured, only the specified paths will be kept alive. + paths?: string[]; +} + +const OUTLET_LIMIT = 5; + +export default function KeepAliveOutlet(props: OutletProps) { if (!Activity) { throw new Error('`` now requires react experimental version. Please install it first.'); } const [outlets, setOutlets] = useState([]); const location = useLocation(); const outlet = useOutlet(); + const outletLimit = props.limit || OUTLET_LIMIT; + const keepAlivePaths = props.paths; + // Save the first outlet for SSR hydration. const outletRef = useRef({ key: location.key, pathname: location.pathname, outlet, }); - useEffect(() => { // If outlets is empty, save the first outlet for SSR hydration, // and should not call setOutlets to avoid re-render. if (outlets.length !== 0 || outletRef.current?.pathname !== location.pathname) { let currentOutlets = outletRef.current ? [outletRef.current] : outlets; + if (keepAlivePaths && keepAlivePaths.length > 0) { + currentOutlets = currentOutlets.filter(o => keepAlivePaths.includes(o.pathname)); + } const result = currentOutlets.some(o => o.pathname === location.pathname); if (!result) { setOutlets([ - // TODO: the max length of outlets should be configurable. ...currentOutlets, { key: location.key, pathname: location.pathname, outlet, }, - ]); + ].slice(-outletLimit)); outletRef.current = null; } } - }, [location.pathname, location.key, outlet, outlets]); + }, [location.pathname, location.key, outlet, outlets, outletLimit, keepAlivePaths]); // Render initail outlet for SSR hydration. const renderOutlets = outlets.length === 0 ? [outletRef.current] : outlets; From ac36776ff01b6ae3e8375e0ad83ece6296d96b43 Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Fri, 15 Mar 2024 10:26:50 +0800 Subject: [PATCH 03/10] Feat: support add plugin by cli option (#6829) * feat: support add plugin by cli option * fix: resolve path of custom plugin --- .changeset/olive-wolves-dress.md | 5 +++++ packages/ice/bin/ice-cli.mjs | 1 + packages/ice/src/config.ts | 4 ++++ packages/ice/src/createService.ts | 12 +++++++++++- 4 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 .changeset/olive-wolves-dress.md diff --git a/.changeset/olive-wolves-dress.md b/.changeset/olive-wolves-dress.md new file mode 100644 index 0000000000..760db56f11 --- /dev/null +++ b/.changeset/olive-wolves-dress.md @@ -0,0 +1,5 @@ +--- +'@ice/app': patch +--- + +feat: support add plugin by cli option diff --git a/packages/ice/bin/ice-cli.mjs b/packages/ice/bin/ice-cli.mjs index 72b3c1ede2..0763b4a98a 100755 --- a/packages/ice/bin/ice-cli.mjs +++ b/packages/ice/bin/ice-cli.mjs @@ -29,6 +29,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); .option('--analyzer', 'visualize size of output files', false) .option('--config ', 'use custom config') .option('--rootDir ', 'project root directory', cwd) + .option('--plugin ', 'add ice plugin by npm package') .action(async ({ rootDir, ...commandArgs }, ctx) => { renamePlatformToTarget(commandArgs); process.env.NODE_ENV = 'production'; diff --git a/packages/ice/src/config.ts b/packages/ice/src/config.ts index efc4c979c8..3f3ed12517 100644 --- a/packages/ice/src/config.ts +++ b/packages/ice/src/config.ts @@ -576,6 +576,10 @@ const cliOption = [ name: 'mock', commands: ['start'], }, + { + name: 'plugin', + commands: ['start', 'build', 'test'], + }, ]; const defaultUserConfig = {}; diff --git a/packages/ice/src/createService.ts b/packages/ice/src/createService.ts index 1d1afcb26d..d9e44603e7 100644 --- a/packages/ice/src/createService.ts +++ b/packages/ice/src/createService.ts @@ -57,6 +57,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt const coreTemplate = path.join(templateDir, 'core/'); const configFile = commandArgs.config || 'ice.config.(mts|mjs|ts|js|cjs|json)'; const dataCache = new Map(); + const builtinPlugin = commandArgs.plugin as string; const generator = new Generator({ // Directory of templates includes `core` and `exports`. templateDir, @@ -161,7 +162,16 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt if (target === WEB) { plugins.push(pluginWeb()); } - + if (builtinPlugin) { + try { + const pluginModule = await dynamicImport(builtinPlugin.startsWith('.') ? path.join(rootDir, builtinPlugin) : builtinPlugin); + const plugin = pluginModule.default || pluginModule; + plugins.push(plugin()); + } catch (err) { + logger.error(`Load builtin plugin error, Faild to import plugin "${builtinPlugin}".`); + throw err; + } + } // Register framework level API. RUNTIME_EXPORTS.forEach(exports => { generatorAPI.addExport(exports); From 0d3cfd5929018a291c803a03e5f0d7c622c15866 Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Tue, 19 Mar 2024 14:04:12 +0800 Subject: [PATCH 04/10] Refactor: use the same compiler when build data-loader (#6804) * fix: update rspack version * feat: compile data loader * chore: dependencies * feat: refactor build data-loader * chore: changelog * fix: add error handle for data loader compiler --- .changeset/khaki-parrots-invite.md | 9 ++ .../ice/src/bundler/config/middlewares.ts | 10 +++ packages/ice/src/bundler/rspack/getConfig.ts | 61 +++++++++++--- packages/ice/src/bundler/rspack/index.ts | 32 +++++++- packages/ice/src/bundler/rspack/start.ts | 4 +- packages/ice/src/bundler/types.ts | 1 + packages/ice/src/constant.ts | 11 ++- packages/ice/src/createService.ts | 2 + .../src/middlewares/dataLoaderMiddleware.ts | 68 +++++++++++++++ packages/ice/src/plugins/task.ts | 1 - .../ice/src/utils/renderExportsTemplate.ts | 2 +- packages/rspack-config/src/index.ts | 82 ++++++++++++++++--- packages/runtime/package.json | 3 +- packages/runtime/src/dataLoader.ts | 4 +- packages/shared-config/src/types.ts | 5 +- 15 files changed, 259 insertions(+), 36 deletions(-) create mode 100644 .changeset/khaki-parrots-invite.md create mode 100644 packages/ice/src/middlewares/dataLoaderMiddleware.ts diff --git a/.changeset/khaki-parrots-invite.md b/.changeset/khaki-parrots-invite.md new file mode 100644 index 0000000000..5e8f6ae192 --- /dev/null +++ b/.changeset/khaki-parrots-invite.md @@ -0,0 +1,9 @@ +--- +'@ice/rspack-config': patch +'@ice/shared-config': patch +'@ice/bundles': patch +'@ice/runtime': patch +'@ice/app': patch +--- + +refactor: the compilation for data-loader diff --git a/packages/ice/src/bundler/config/middlewares.ts b/packages/ice/src/bundler/config/middlewares.ts index 5cb6851e7f..6feeb65307 100644 --- a/packages/ice/src/bundler/config/middlewares.ts +++ b/packages/ice/src/bundler/config/middlewares.ts @@ -1,9 +1,11 @@ +import type { Compiler } from '@rspack/core'; import type { Configuration as DevServerConfiguration } from 'webpack-dev-server'; import type { TaskConfig } from 'build-scripts'; import type { RenderMode } from '@ice/runtime'; import type { Config } from '@ice/shared-config/types'; import createMockMiddleware from '../../middlewares/mock/createMiddleware.js'; import createRenderMiddleware from '../../middlewares/renderMiddleware.js'; +import createDataLoaderMiddleware from '../../middlewares/dataLoaderMiddleware.js'; import type { UserConfig } from '../../types/userConfig.js'; import type RouteManifest from '../../utils/routeManifest.js'; import type { GetAppConfig } from '../../types/plugin.js'; @@ -16,6 +18,7 @@ interface SetupOptions { excuteServerEntry: () => Promise; mock: boolean; rootDir: string; + dataLoaderCompiler?: Compiler; } function setupMiddlewares(middlewares: Parameters[0], { @@ -26,6 +29,7 @@ function setupMiddlewares(middlewares: Parameters name === 'serve-index'); middlewares.splice( diff --git a/packages/ice/src/bundler/rspack/getConfig.ts b/packages/ice/src/bundler/rspack/getConfig.ts index 81eecadbd3..955f9a5b0d 100644 --- a/packages/ice/src/bundler/rspack/getConfig.ts +++ b/packages/ice/src/bundler/rspack/getConfig.ts @@ -1,4 +1,6 @@ +import * as path from 'path'; import getRspackConfig from '@ice/rspack-config'; +import type { TaskConfig } from 'build-scripts'; import type { Configuration, rspack as Rspack } from '@rspack/core'; import type { Config } from '@ice/shared-config/types'; import { getRouteExportConfig } from '../../service/config.js'; @@ -11,7 +13,6 @@ import { } from '../../constant.js'; import { getReCompilePlugin, getServerPlugin, getSpinnerPlugin } from '../config/plugins.js'; import { getExpandedEnvs } from '../../utils/runtimeEnv.js'; -import DataLoaderPlugin from '../../webpack/DataLoaderPlugin.js'; import type { BundlerOptions, Context } from '../types.js'; type GetConfig = ( @@ -33,16 +34,14 @@ const getConfig: GetConfig = async (context, options, rspack) => { const { rootDir, userConfig, - getAllPlugin, extendsPluginAPI: { serverCompileTask, getRoutesFile, - generator, }, } = context; const { reCompile, ensureRoutesConfig } = getRouteExportConfig(rootDir); const getPlugins = (taskConfig: Config): Config['plugins'] => { - const { target, outputDir, useDataLoader, server } = taskConfig; + const { target, outputDir, server } = taskConfig; return [ // Add spinner for webpack task. getSpinnerPlugin(spinner), @@ -60,14 +59,6 @@ const getConfig: GetConfig = async (context, options, rspack) => { }), // Add ReCompile plugin when routes config changed. getReCompilePlugin(reCompile, routeManifest), - // Add DataLoader plugin. - useDataLoader && new DataLoaderPlugin({ - serverCompiler, - target, - rootDir, - getAllPlugin, - frameworkExports: generator.getExportList('framework', target), - }), ].filter(Boolean) as Config['plugins']; }; return await Promise.all(taskConfigs.map(async ({ config }) => { @@ -91,5 +82,51 @@ const getConfig: GetConfig = async (context, options, rspack) => { })); }; +type GetDataLoaderRspackConfig = ( + context: Context, + task: TaskConfig, + rspack: typeof Rspack, +) => Promise; + +export const getDataLoaderConfig: GetDataLoaderRspackConfig = async (context, task, rspack) => { + const { + rootDir, + extendsPluginAPI: { + generator, + }, + } = context; + const { config } = task; + const frameworkExports = generator.getExportList('framework', config.target); + return await getRspackConfig({ + rootDir, + rspack, + runtimeTmpDir: RUNTIME_TMP_DIR, + getExpandedEnvs, + runtimeDefineVars: { + [IMPORT_META_TARGET]: JSON.stringify(config.target), + [IMPORT_META_RENDERER]: JSON.stringify('client'), + }, + localIdentName: config.cssModules?.localIdentName || (config.mode === 'development' ? CSS_MODULES_LOCAL_IDENT_NAME_DEV : CSS_MODULES_LOCAL_IDENT_NAME), + taskConfig: { + ...config, + // Override task config for dataLoader. + assetsManifest: false, + entry: { + 'data-loader': path.join(rootDir, RUNTIME_TMP_DIR, 'data-loader.ts'), + }, + swcOptions: { + keepExports: ['dataLoader'], + }, + splitChunks: false, + redirectImports: frameworkExports, + // Data loader should be hot reload in development mode. + fastRefresh: false, + devServer: { + hot: false, + }, + name: 'dataLoader', + }, + }); +}; export default getConfig; diff --git a/packages/ice/src/bundler/rspack/index.ts b/packages/ice/src/bundler/rspack/index.ts index aec155cb97..ebb8c5b43c 100644 --- a/packages/ice/src/bundler/rspack/index.ts +++ b/packages/ice/src/bundler/rspack/index.ts @@ -1,8 +1,9 @@ -import type { MultiCompiler, rspack as Rspack } from '@rspack/core'; +import type { MultiCompiler, Compiler, rspack as Rspack } from '@rspack/core'; import type { RspackDevServer } from '@rspack/dev-server'; import { logger } from '../../utils/logger.js'; import type { BundlerOptions, Context } from '../types.js'; -import getConfig from './getConfig.js'; +import { WEB } from '../../constant.js'; +import getConfig, { getDataLoaderConfig } from './getConfig.js'; import start from './start.js'; import build from './build.js'; @@ -16,13 +17,38 @@ async function bundler( hooksAPI, routeManifest, appConfig, + hasDataLoader, } = options; let compiler: MultiCompiler; + let dataLoaderCompiler: Compiler; let devServer: RspackDevServer; const { rspack } = await import('@ice/bundles/esm/rspack.js'); // Override the type of rspack, because of rspack is imported from pre-compiled bundle. const rspackConfigs = await getConfig(context, options, rspack as unknown as typeof Rspack); try { + if (hasDataLoader) { + const dataLoaderRspackConfig = await getDataLoaderConfig( + context, + taskConfigs.find(({ name }) => name === WEB), + rspack as unknown as typeof Rspack, + ); + if (command === 'start') { + // Create a special compiler for dataLoader, + // it will be used in dev-server middleware. + // @ts-ignore + dataLoaderCompiler = rspack(dataLoaderRspackConfig); + } else if (command === 'build') { + // Build parrallel when build. + rspackConfigs.push(dataLoaderRspackConfig); + // Override the output options of clean to false, + // Otherwise, the output of previous build will be cleaned. + rspackConfigs.forEach((config) => { + if (config?.output?.clean) { + config.output.clean = false; + } + }); + } + } // @ts-ignore compiler = rspack(rspackConfigs); } catch (error) { @@ -40,7 +66,7 @@ async function bundler( }; if (command === 'start') { // @ts-expect-error dev-server has been pre-packed, so it will have different type. - devServer = await start(buildOptions); + devServer = await start(buildOptions, dataLoaderCompiler); } else if (command === 'build') { await build(buildOptions); } diff --git a/packages/ice/src/bundler/rspack/start.ts b/packages/ice/src/bundler/rspack/start.ts index 691bf29e1d..d03153d1c8 100644 --- a/packages/ice/src/bundler/rspack/start.ts +++ b/packages/ice/src/bundler/rspack/start.ts @@ -1,3 +1,4 @@ +import type { Compiler } from '@rspack/core'; import type { Configuration as DevServerConfiguration } from '@rspack/dev-server'; import getDefaultServerConfig from '../config/defaultServerConfig.js'; import getMiddlewares from '../config/middlewares.js'; @@ -15,7 +16,7 @@ const start = async ({ compiler, appConfig, hooksAPI, -}: BuildOptions) => { +}: BuildOptions, dataLoaderCompiler?: Compiler) => { const { rootDir, applyHook, commandArgs, userConfig, extendsPluginAPI: { excuteServerEntry } } = context; const customMiddlewares = rspackConfigs[0].devServer?.setupMiddlewares; const defaultConfig = await getDefaultServerConfig(rspackConfigs[0].devServer, commandArgs); @@ -32,6 +33,7 @@ const start = async ({ excuteServerEntry, mock: commandArgs.mock, rootDir, + dataLoaderCompiler, }); return customMiddlewares ? customMiddlewares(builtInMiddlewares, devServer) : builtInMiddlewares; }, diff --git a/packages/ice/src/bundler/types.ts b/packages/ice/src/bundler/types.ts index 304af0ed63..0cf4f110ed 100644 --- a/packages/ice/src/bundler/types.ts +++ b/packages/ice/src/bundler/types.ts @@ -38,6 +38,7 @@ export interface BundlerOptions { configFile: string; userConfig: UserConfig; routeManifest: RouteManifest; + hasDataLoader: boolean; } export type CompileResults = { diff --git a/packages/ice/src/constant.ts b/packages/ice/src/constant.ts index 6fed8c2746..bf7a6969f2 100644 --- a/packages/ice/src/constant.ts +++ b/packages/ice/src/constant.ts @@ -67,9 +67,6 @@ export const RUNTIME_EXPORTS = [ 'useSuspenseData', 'usePublicAppContext', 'Await', - 'defineDataLoader', - 'defineServerDataLoader', - 'defineStaticDataLoader', 'usePageLifecycle', 'unstable_useDocumentData', ], @@ -78,6 +75,14 @@ export const RUNTIME_EXPORTS = [ }, source: '@ice/runtime', }, + { + specifier: [ + 'defineDataLoader', + 'defineServerDataLoader', + 'defineStaticDataLoader', + ], + source: '@ice/runtime/data-loader', + }, ]; export const CSS_MODULES_LOCAL_IDENT_NAME = '[local]_[hash:8]'; diff --git a/packages/ice/src/createService.ts b/packages/ice/src/createService.ts index d9e44603e7..f37ee2bad6 100644 --- a/packages/ice/src/createService.ts +++ b/packages/ice/src/createService.ts @@ -295,6 +295,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt dataCache.set('routes', JSON.stringify(routesInfo)); dataCache.set('hasExportAppData', hasExportAppData ? 'true' : ''); + const hasDataLoader = Boolean(userConfig.dataLoader) && (hasExportAppData || Boolean(routesInfo.loaders)); // Render exports files if route component export dataLoader / pageConfig. renderExportsTemplate( { @@ -396,6 +397,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt }, userConfig, configFile, + hasDataLoader, }; try { if (command === 'test') { diff --git a/packages/ice/src/middlewares/dataLoaderMiddleware.ts b/packages/ice/src/middlewares/dataLoaderMiddleware.ts new file mode 100644 index 0000000000..ad3365c663 --- /dev/null +++ b/packages/ice/src/middlewares/dataLoaderMiddleware.ts @@ -0,0 +1,68 @@ +import type { IncomingMessage } from 'http'; +import { parse } from 'url'; +import crypto from 'crypto'; +import type { Compiler } from '@rspack/core'; +import type { ExpressRequestHandler, Middleware } from 'webpack-dev-server'; +import { logger } from '../utils/logger.js'; + +function etag(buf: Buffer) { + return crypto.createHash('sha256').update(buf).digest('hex'); +} + +export default function createDataLoaderMiddleware(compiler: Compiler): Middleware { + const watchOptions = compiler.options.watchOptions || {}; + const watching = compiler.watch(watchOptions, ( + error, + ) => { + if (error) { + console.error(error); + } + }); + const compileTask = new Promise((resolve, reject) => { + compiler.hooks.done.tap('data-loader-compiler', (stats) => { + const statsJson = stats.toJson({ + all: false, + }); + if (!stats.hasErrors() || !statsJson?.errors?.length) { + resolve(watching); + } else if (statsJson?.errors?.length > 0) { + logger.error('[data-loader] Compile failed:'); + logger.log(statsJson?.errors); + reject(false); + } + }); + }); + + const middleware: ExpressRequestHandler = async function (req: IncomingMessage, res: any, next: () => void) { + const { method, url } = req; + if (method !== 'GET') { + return next(); + } + const publicPath = compiler.options.output?.publicPath + ? `${compiler.options.output.publicPath.replace(/\/$/, '')}/` + : '/'; + const filePath = parse(url || '').pathname; + const filename = filePath?.startsWith(publicPath) ? filePath.slice(publicPath.length) : filePath.slice(1); + // Mark sure the compiler is ready. + await compileTask; + const buffer = compiler.getAsset(filename); + + if (!buffer) { + return next(); + } + const calcEtag = etag(buffer); + const oldEtag = req.headers['if-none-match']; + // Only data-loader.js will be matched. + res.setHeader('Content-Type', 'text/javascript'); + res.setHeader('ETag', calcEtag); + if (calcEtag === oldEtag) { + res.status(304).send(); + } else { + res.send(buffer); + } + }; + return { + name: 'data-loader-middleware', + middleware, + }; +} diff --git a/packages/ice/src/plugins/task.ts b/packages/ice/src/plugins/task.ts index 03c75d9db1..3dd7e80e5a 100644 --- a/packages/ice/src/plugins/task.ts +++ b/packages/ice/src/plugins/task.ts @@ -28,7 +28,6 @@ const getDefaultTaskConfig = ({ rootDir, command }): Config => { 'universal-env': envReplacement, '@uni/env': envReplacement, }, - assetsManifest: true, fastRefresh: command === 'start', logging: process.env.WEBPACK_LOGGING || defaultLogging, diff --git a/packages/ice/src/utils/renderExportsTemplate.ts b/packages/ice/src/utils/renderExportsTemplate.ts index e24eccb176..a02d20bb46 100644 --- a/packages/ice/src/utils/renderExportsTemplate.ts +++ b/packages/ice/src/utils/renderExportsTemplate.ts @@ -38,4 +38,4 @@ function renderExportsTemplate( }); } -export default renderExportsTemplate; \ No newline at end of file +export default renderExportsTemplate; diff --git a/packages/rspack-config/src/index.ts b/packages/rspack-config/src/index.ts index 58c819674e..84e474a60c 100644 --- a/packages/rspack-config/src/index.ts +++ b/packages/rspack-config/src/index.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import { createRequire } from 'module'; import { getDefineVars, getCompilerPlugins, getJsxTransformOptions, getAliasWithRoot, skipCompilePackages, getDevtoolValue } from '@ice/shared-config'; -import type { Config, ModifyWebpackConfig } from '@ice/shared-config/types'; +import type { Config, ModifyWebpackConfig, ImportDeclaration } from '@ice/shared-config/types'; import type { Configuration, rspack as Rspack } from '@rspack/core'; import lodash from '@ice/bundles/compiled/lodash/index.js'; import { coreJsPath } from '@ice/bundles'; @@ -33,10 +33,41 @@ interface BuiltinFeatures { assetsManifest?: boolean; } +interface TransformFeatures { + keepExport?: string[]; + removeExport?: string[]; + optimizeImport?: string[]; + importConfig?: { + name: string; + map: Record; + }[]; +} + const require = createRequire(import.meta.url); const { merge } = lodash; +function formatRedirectImports(redirectImports: ImportDeclaration[]) { + // Transform frameworkExports to swc options. + const runtimeRedirect = {}; + redirectImports.forEach(({ specifier, source }) => { + if (Array.isArray(specifier)) { + specifier.forEach((name) => { + runtimeRedirect[name] = { + to: source, + importType: 'Named', + }; + }); + } else { + runtimeRedirect[specifier] = { + to: source, + importType: 'Default', + }; + } + }); + return runtimeRedirect; +} + const getConfig: GetConfig = async (options) => { const { rootDir, @@ -49,6 +80,7 @@ const getConfig: GetConfig = async (options) => { } = options; const { + name, cacheDir, mode, minify, @@ -71,6 +103,10 @@ const getConfig: GetConfig = async (options) => { configureWebpack = [], minimizerOptions = {}, optimizePackageImports = [], + entry, + assetsManifest, + redirectImports, + fastRefresh, sourceMap, } = taskConfig || {}; const isDev = mode === 'development'; @@ -80,7 +116,12 @@ const getConfig: GetConfig = async (options) => { const { rspack: { DefinePlugin, ProvidePlugin, SwcJsMinimizerRspackPlugin } } = await import('@ice/bundles/esm/rspack.js'); const cssFilename = `css/${hashKey ? `[name]-[${hashKey}].css` : '[name].css'}`; // get compile plugins - const compilerWebpackPlugins = getCompilerPlugins(rootDir, taskConfig || {}, 'rspack', { isServer: false }); + const compilerWebpackPlugins = getCompilerPlugins(rootDir, { + ...(taskConfig || {}), + // Override redirectImports to empty array, + // it's supported by built-in loader in speedup mode. + redirectImports: undefined, + }, 'rspack', { isServer: false }); const jsMinimizerPluginOptions: any = merge({ compress: { ecma: 5, @@ -104,7 +145,7 @@ const getConfig: GetConfig = async (options) => { module: true, }, minimizerOptions); const builtinFeatures: BuiltinFeatures = { - assetsManifest: true, + assetsManifest, }; let splitChunksStrategy = null; // Use builtin splitChunks strategy by default. @@ -131,11 +172,32 @@ const getConfig: GetConfig = async (options) => { return `${pkg}[\\/]|_${pkg.replace('/', '_')}@[^/]+[\\/]`; }).join('|')}).*`; } + const transformFeatures: TransformFeatures = { + removeExport: swcOptions.removeExportExprs, + // Function type of keepExports is not supported yet. + keepExport: swcOptions.keepExports as string[], + optimizeImport: optimizePackageImports, + }; + + if (redirectImports?.length > 0) { + transformFeatures.importConfig = [{ + name: 'ice', + map: formatRedirectImports(redirectImports), + }, { + name: '@ice/runtime', + map: { + dataLoader: { + to: '@ice/runtime/data-loader', + importType: 'Named', + }, + }, + }]; + } const config: Configuration = { - entry: { + entry: entry || { main: [path.join(rootDir, runtimeTmpDir, 'entry.client.tsx')], }, - name: 'web', + name: name || 'web', mode, externals, output: { @@ -156,12 +218,8 @@ const getConfig: GetConfig = async (options) => { use: { loader: 'builtin:compilation-loader', options: { - swcOptions: getJsxTransformOptions({ suffix: 'jsx', rootDir, mode, fastRefresh: isDev, polyfill, enableEnv: true }), - transformFeatures: { - removeExport: swcOptions.removeExportExprs, - keepExport: swcOptions.keepExports, - optimizeImport: optimizePackageImports, - }, + swcOptions: getJsxTransformOptions({ suffix: 'jsx', rootDir, mode, fastRefresh: isDev && fastRefresh, polyfill, enableEnv: true }), + transformFeatures, compileRules: { // "bundles/compiled" is the path when using @ice/bundles. exclude: [...compileExclude, 'bundles/compiled'], @@ -215,7 +273,7 @@ const getConfig: GetConfig = async (options) => { ...plugins, // Unplugin should be compatible with rspack. ...compilerWebpackPlugins, - isDev && new RefreshPlugin(), + isDev && fastRefresh && new RefreshPlugin(), new DefinePlugin(getDefineVars(define, runtimeDefineVars, getExpandedEnvs)), new ProvidePlugin({ process: [require.resolve('process/browser')], diff --git a/packages/runtime/package.json b/packages/runtime/package.json index d0ffa9ddda..f949a30dcd 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -20,7 +20,8 @@ "./polyfills/abortcontroller": "./esm/polyfills/abortcontroller.js", "./react": "./esm/react.js", "./react/jsx-runtime": "./esm/jsx-runtime.js", - "./react/jsx-dev-runtime": "./esm/jsx-dev-runtime.js" + "./react/jsx-dev-runtime": "./esm/jsx-dev-runtime.js", + "./data-loader": "./esm/dataLoader.js" }, "files": [ "esm", diff --git a/packages/runtime/src/dataLoader.ts b/packages/runtime/src/dataLoader.ts index 4e2f204fb9..c37b3b178e 100644 --- a/packages/runtime/src/dataLoader.ts +++ b/packages/runtime/src/dataLoader.ts @@ -274,6 +274,8 @@ async function init(loaders: Loaders, options: Options) { }; } -export default { +export const dataLoader = { init, }; + +export default dataLoader; diff --git a/packages/shared-config/src/types.ts b/packages/shared-config/src/types.ts index d1a7722e8b..e284ab9038 100644 --- a/packages/shared-config/src/types.ts +++ b/packages/shared-config/src/types.ts @@ -47,7 +47,7 @@ interface SwcOptions { nodeTransform?: boolean; } -interface ImportDeclaration { +export interface ImportDeclaration { specifier?: string | string[]; source: string; type?: boolean; @@ -79,6 +79,9 @@ export type { webpack }; type PluginFunction = (this: Compiler, compiler: Compiler) => void; export interface Config { + // The name of the task, used for the output log. + name?: string; + target?: string; mode?: 'none' | 'development' | 'production'; From d0a748f6d4b6bdb6fb966f407afbc48bd1acc20a Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Tue, 19 Mar 2024 14:58:18 +0800 Subject: [PATCH 05/10] Fix: ignore basename in single route mode when route do not match (#6833) * fix: compat with the route path did not match when single route mode * fix: route do not match * Update singleRouter.tsx --- .changeset/metal-turtles-design.md | 5 +++++ packages/runtime/src/singleRouter.tsx | 10 ++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) create mode 100644 .changeset/metal-turtles-design.md diff --git a/.changeset/metal-turtles-design.md b/.changeset/metal-turtles-design.md new file mode 100644 index 0000000000..2b2f421240 --- /dev/null +++ b/.changeset/metal-turtles-design.md @@ -0,0 +1,5 @@ +--- +'@ice/runtime': patch +--- + +fix: compat with the route path did not match when single route mode diff --git a/packages/runtime/src/singleRouter.tsx b/packages/runtime/src/singleRouter.tsx index 14c6a40c3c..fda96b0f85 100644 --- a/packages/runtime/src/singleRouter.tsx +++ b/packages/runtime/src/singleRouter.tsx @@ -257,8 +257,14 @@ export const matchRoutes = ( location: Partial | string, basename: string, ) => { - const pathname = typeof location === 'string' ? location : location.pathname; - const stripedPathname = stripBasename(pathname || '/', basename || '/'); + const pathname = (typeof location === 'string' ? location : location.pathname) || '/'; + + let stripedPathname = stripBasename(pathname, basename || '/'); + if (!stripedPathname && basename !== '/') { + // If pathname is not match, we should ignore the basename, + // in case of the basename is customized. + stripedPathname = stripBasename(pathname, '/'); + } let branches = flattenRoutes(routes); if (branches.length === 1) { // Just one branch, no need to match. From 8275f13f81453f422d77adc8478be8564323c5d2 Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Tue, 19 Mar 2024 15:00:39 +0800 Subject: [PATCH 06/10] Feat: upgrade pack-binding for new features (#6832) * feat: upgrade icepack for new features * chore: changeset --- .changeset/good-pans-joke.md | 7 + package.json | 2 +- packages/bundles/package.json | 8 +- packages/ice/package.json | 4 +- .../ice/src/bundler/rspack/formatStats.ts | 5 +- packages/ice/tsconfig.json | 2 +- packages/rspack-config/package.json | 2 +- ...@0.5.4.patch => @rspack__core@0.5.7.patch} | 11 +- pnpm-lock.yaml | 184 +++++++++--------- 9 files changed, 113 insertions(+), 112 deletions(-) create mode 100644 .changeset/good-pans-joke.md rename patches/{@rspack__core@0.5.4.patch => @rspack__core@0.5.7.patch} (83%) diff --git a/.changeset/good-pans-joke.md b/.changeset/good-pans-joke.md new file mode 100644 index 0000000000..906286b068 --- /dev/null +++ b/.changeset/good-pans-joke.md @@ -0,0 +1,7 @@ +--- +'@ice/rspack-config': patch +'@ice/bundles': patch +'@ice/app': patch +--- + +feat: upgrade icepack for new features diff --git a/package.json b/package.json index c57f2d6064..d66ef5646c 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "packageManager": "pnpm@8.9.2", "pnpm": { "patchedDependencies": { - "@rspack/core@0.5.4": "patches/@rspack__core@0.5.4.patch", + "@rspack/core@0.5.7": "patches/@rspack__core@0.5.7.patch", "unplugin@1.6.0": "patches/unplugin@1.6.0.patch" } } diff --git a/packages/bundles/package.json b/packages/bundles/package.json index 2c7c2fc9dc..eb16f54e2f 100644 --- a/packages/bundles/package.json +++ b/packages/bundles/package.json @@ -45,13 +45,13 @@ "zod": "^3.22.3", "zod-validation-error": "1.2.0", "terminal-link": "^2.1.1", - "@ice/pack-binding": "0.0.11", + "@ice/pack-binding": "0.0.12", "mime-types": "2.1.35" }, "devDependencies": { - "@rspack/plugin-react-refresh": "0.5.4", - "@rspack/dev-server": "0.5.4", - "@rspack/core": "0.5.4", + "@rspack/plugin-react-refresh": "0.5.7", + "@rspack/dev-server": "0.5.7", + "@rspack/core": "0.5.7", "@types/less": "^3.0.3", "@types/lodash": "^4.14.181", "@types/webpack-bundle-analyzer": "^4.4.1", diff --git a/packages/ice/package.json b/packages/ice/package.json index 946e1e7981..09e218a8e8 100644 --- a/packages/ice/package.json +++ b/packages/ice/package.json @@ -98,8 +98,8 @@ "unplugin": "^1.6.0", "webpack": "^5.88.0", "webpack-dev-server": "4.15.0", - "@rspack/core": "0.5.4", - "@rspack/dev-server": "0.5.4" + "@rspack/core": "0.5.7", + "@rspack/dev-server": "0.5.7" }, "peerDependencies": { "react": ">=18.0.0", diff --git a/packages/ice/src/bundler/rspack/formatStats.ts b/packages/ice/src/bundler/rspack/formatStats.ts index dc2ba518e6..7a4a9929c6 100644 --- a/packages/ice/src/bundler/rspack/formatStats.ts +++ b/packages/ice/src/bundler/rspack/formatStats.ts @@ -1,12 +1,13 @@ import chalk from 'chalk'; import type { Stats, MultiStats } from '@rspack/core'; +import type { StatsCompilation } from 'webpack'; import formatWebpackMessages from '../../utils/formatWebpackMessages.js'; function formatStats(stats: Stats | MultiStats, showWarnings = true) { const statsData = stats.toJson({ preset: 'errors-warnings', - }); - // @ts-ignore + }) as StatsCompilation; + const { errors, warnings } = formatWebpackMessages(statsData); if (errors.length) { diff --git a/packages/ice/tsconfig.json b/packages/ice/tsconfig.json index ce00f8369f..fced433d20 100644 --- a/packages/ice/tsconfig.json +++ b/packages/ice/tsconfig.json @@ -7,5 +7,5 @@ "moduleDetection": "legacy" }, "include": ["src"], - "exclude": ["src/shims/*"] + "exclude": ["src/utils/*"] } diff --git a/packages/rspack-config/package.json b/packages/rspack-config/package.json index 991ecfa968..7dc61377cb 100644 --- a/packages/rspack-config/package.json +++ b/packages/rspack-config/package.json @@ -19,7 +19,7 @@ "@ice/shared-config": "1.2.5" }, "devDependencies": { - "@rspack/core": "0.5.4" + "@rspack/core": "0.5.7" }, "scripts": { "watch": "tsc -w --sourceMap", diff --git a/patches/@rspack__core@0.5.4.patch b/patches/@rspack__core@0.5.7.patch similarity index 83% rename from patches/@rspack__core@0.5.4.patch rename to patches/@rspack__core@0.5.7.patch index 8c0848fea2..1517ff1009 100644 --- a/patches/@rspack__core@0.5.4.patch +++ b/patches/@rspack__core@0.5.7.patch @@ -1,5 +1,5 @@ diff --git a/dist/config/adapter.js b/dist/config/adapter.js -index 49122b3e9f4f0ac85b4075a98f693986b4333051..c3436a090fdbac00e555b2e308974f8d3f9c2426 100644 +index 4eebbcf79cba29acbc0a36d565acc1c08eaf790b..1d87c9be33f69b8dda1436d8e3b970ce0b571112 100644 --- a/dist/config/adapter.js +++ b/dist/config/adapter.js @@ -15,6 +15,7 @@ const getRawOptions = (options, compiler) => { @@ -11,7 +11,7 @@ index 49122b3e9f4f0ac85b4075a98f693986b4333051..c3436a090fdbac00e555b2e308974f8d target: getRawTarget(options.target), context: options.context, diff --git a/dist/config/defaults.js b/dist/config/defaults.js -index aeb7b74dd8473fa049002cf710ae860577d6d2e2..0dd4fd09fd08482b5a2c5a82cad61ab70e2b2d68 100644 +index 1f9f61ff680b6db026c43eb95fe2d78c5f5d8195..56ce90247fd920717d42bc16864e6025fe6dca66 100644 --- a/dist/config/defaults.js +++ b/dist/config/defaults.js @@ -53,6 +53,11 @@ const applyRspackOptionsDefaults = (options) => { @@ -41,7 +41,7 @@ index aeb7b74dd8473fa049002cf710ae860577d6d2e2..0dd4fd09fd08482b5a2c5a82cad61ab7 D(experiments, "lazyCompilation", false); D(experiments, "asyncWebAssembly", false); diff --git a/dist/config/normalization.js b/dist/config/normalization.js -index 72167c504bd43f606481ccd1de0bdcb9eae71d9f..b16f9f3bbf1c45e00a9ca31684cefec55198683b 100644 +index 696eddf849f8a2f2c66237cb37db767f4dfe20ca..7e89b6091471de8287ce0785042676873141cfbe 100644 --- a/dist/config/normalization.js +++ b/dist/config/normalization.js @@ -12,6 +12,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); @@ -53,10 +53,10 @@ index 72167c504bd43f606481ccd1de0bdcb9eae71d9f..b16f9f3bbf1c45e00a9ca31684cefec5 ? config.ignoreWarnings.map(ignore => { if (typeof ignore === "function") { diff --git a/dist/config/zod.js b/dist/config/zod.js -index 1c4c2cf4d02c562b8fc965c103de0eaf8e246b6a..7fa7e42a02180081096d77f64d7df0cc7d61b4d1 100644 +index a81260f08e4e7de64ff3c1f8769a658db4c73883..df3184bad831922f64f3c41b64bce08fcdf5b3cd 100644 --- a/dist/config/zod.js +++ b/dist/config/zod.js -@@ -766,6 +766,7 @@ exports.rspackOptions = zod_1.z.strictObject({ +@@ -775,5 +775,6 @@ exports.rspackOptions = zod_1.z.strictObject({ builtins: builtins.optional(), module: moduleOptions.optional(), profile: profile.optional(), @@ -64,4 +64,3 @@ index 1c4c2cf4d02c562b8fc965c103de0eaf8e246b6a..7fa7e42a02180081096d77f64d7df0cc + bail: bail.optional(), + features: zod_1.z.custom().optional(), }); - //# sourceMappingURL=zod.js.map diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 991e6096a0..e5db4cdadc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,9 +5,9 @@ settings: excludeLinksFromLockfile: false patchedDependencies: - '@rspack/core@0.5.4': - hash: cx7wc7uikmrb5dsrfcy5wrjzui - path: patches/@rspack__core@0.5.4.patch + '@rspack/core@0.5.7': + hash: hydgitlae4ar2jrvgl5qp2f2um + path: patches/@rspack__core@0.5.7.patch unplugin@1.6.0: hash: z2z7uvjbiarznogeja262ejlha path: patches/unplugin@1.6.0.patch @@ -1298,8 +1298,8 @@ importers: specifier: 0.0.8 version: 0.0.8 '@ice/pack-binding': - specifier: 0.0.11 - version: 0.0.11 + specifier: 0.0.12 + version: 0.0.12 '@ice/swc-plugin-keep-export': specifier: 0.2.0 version: 0.2.0 @@ -1395,14 +1395,14 @@ importers: specifier: 0.5.10 version: 0.5.10(react-refresh@0.14.0)(webpack-dev-server@4.15.0)(webpack@5.88.2) '@rspack/core': - specifier: 0.5.4 - version: 0.5.4(patch_hash=cx7wc7uikmrb5dsrfcy5wrjzui)(@swc/helpers@0.5.1) + specifier: 0.5.7 + version: 0.5.7(patch_hash=hydgitlae4ar2jrvgl5qp2f2um)(@swc/helpers@0.5.1) '@rspack/dev-server': - specifier: 0.5.4 - version: 0.5.4(@rspack/core@0.5.4)(@types/express@4.17.17)(webpack@5.88.2) + specifier: 0.5.7 + version: 0.5.7(@rspack/core@0.5.7)(@types/express@4.17.17)(webpack@5.88.2) '@rspack/plugin-react-refresh': - specifier: 0.5.4 - version: 0.5.4(react-refresh@0.14.0) + specifier: 0.5.7 + version: 0.5.7(react-refresh@0.14.0) '@types/less': specifier: ^3.0.3 version: 3.0.3 @@ -1722,11 +1722,11 @@ importers: version: 21.1.1 devDependencies: '@rspack/core': - specifier: 0.5.4 - version: 0.5.4(patch_hash=cx7wc7uikmrb5dsrfcy5wrjzui)(@swc/helpers@0.5.1) + specifier: 0.5.7 + version: 0.5.7(patch_hash=hydgitlae4ar2jrvgl5qp2f2um)(@swc/helpers@0.5.1) '@rspack/dev-server': - specifier: 0.5.4 - version: 0.5.4(@rspack/core@0.5.4)(@types/express@4.17.17)(webpack@5.88.2) + specifier: 0.5.7 + version: 0.5.7(@rspack/core@0.5.7)(@types/express@4.17.17)(webpack@5.88.2) '@types/babel__generator': specifier: ^7.6.4 version: 7.6.4 @@ -2314,8 +2314,8 @@ importers: version: link:../shared-config devDependencies: '@rspack/core': - specifier: 0.5.4 - version: 0.5.4(patch_hash=cx7wc7uikmrb5dsrfcy5wrjzui)(@swc/helpers@0.5.1) + specifier: 0.5.7 + version: 0.5.7(patch_hash=hydgitlae4ar2jrvgl5qp2f2um)(@swc/helpers@0.5.1) packages/runtime: dependencies: @@ -6548,8 +6548,8 @@ packages: '@ice/css-modules-hash-win32-x64-msvc': 0.0.8 dev: false - /@ice/pack-binding-darwin-arm64@0.0.11: - resolution: {integrity: sha512-rEehtihZFAhPHXIwwJDgQLCW7nDxR8wVv9uI6XemMgYmhBKkrcHXDPpbuwnlPIepqluXOTV/c1kVIZzEsAFUFg==} + /@ice/pack-binding-darwin-arm64@0.0.12: + resolution: {integrity: sha512-o/obsLWXWCAnvkavQ7I5NFZSULVUKLLoukyO+I0A+ocSQw3Kync/Iu0+3Sm3GX4EVvR082vilj7bWcBgyw2hzA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -6557,16 +6557,16 @@ packages: dev: false optional: true - /@ice/pack-binding-darwin-universal@0.0.11: - resolution: {integrity: sha512-42ExKqjsw0oB+/FiMXObmIESWiqVai6H1xOdxT34afE0zMFkdwFQSdjnqY7giJ9VmXw/lVN6vUKlRlahv0NMZg==} + /@ice/pack-binding-darwin-universal@0.0.12: + resolution: {integrity: sha512-NRGLEvvQ0rBdNc1GdTVh3IbstFj5aNF4Fvp7ZF31XxcnXmlA1lF96cvYJp9FAJhsEvPOpNNcehOvHSDRchxmkw==} engines: {node: '>= 10'} os: [darwin] requiresBuild: true dev: false optional: true - /@ice/pack-binding-darwin-x64@0.0.11: - resolution: {integrity: sha512-jCPS8Hm3xRokHZ3VQpGIRcYlOGL6g8JK+ftb/nYUDCUHlSjzafS398Qn3WpPB5O6nXa2qXctyCrVXrHLsNnAaw==} + /@ice/pack-binding-darwin-x64@0.0.12: + resolution: {integrity: sha512-htMqQvotrye4O43IfebRgI83fy97+reJwuJB+SDGAI7hzj8d6cLrMrOy5DDFlOr2xHRo6nyALJUu1A5Vmu1z6A==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -6574,8 +6574,8 @@ packages: dev: false optional: true - /@ice/pack-binding-linux-x64-gnu@0.0.11: - resolution: {integrity: sha512-IRchi7VuNTVoOIsp5GVPe9F6H1ZG2jr2u79f9UXT4Xqv+OeUund6GngP1X0jPfvXzYNR2PY/+Ox7biynxOMVtw==} + /@ice/pack-binding-linux-x64-gnu@0.0.12: + resolution: {integrity: sha512-5gW2eGgCok+2SJXS9D4pdkjWDCx5zyvwNhGOviOlsUPgXYCfN8WyVlSX1sWVXDyb76Lckl8IjjtiCi5PBWy0cA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -6583,8 +6583,8 @@ packages: dev: false optional: true - /@ice/pack-binding-linux-x64-musl@0.0.11: - resolution: {integrity: sha512-+8HRztvg2eDJID5+wtf6mJBkNBSSywnLeWBBvVyWXl4wzcpWLHmizXv28g4VMXXLlkqMD1xAXdsO/iKKqsdvGA==} + /@ice/pack-binding-linux-x64-musl@0.0.12: + resolution: {integrity: sha512-hdKXdq0nWAzdMD+sNSBw1ODqADffknCIsU+E8Qz8FnsK8tpwoh0dzLb8aKrr9yBpCtM+yPUAtIqDVh36WClZ7A==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -6592,8 +6592,8 @@ packages: dev: false optional: true - /@ice/pack-binding-win32-arm64-msvc@0.0.11: - resolution: {integrity: sha512-4y5SC2sVc5XWgdPN4lZWC5fZcXpHM0oVcbhkIYkxQuYv8Tx6P4gZZh3pfqt95KCmqBjcikBVZ9uZw0NTEuRd1Q==} + /@ice/pack-binding-win32-arm64-msvc@0.0.12: + resolution: {integrity: sha512-d96DmLUxZ8cgFVbBm30f9CI3H6GDtq9Bh7fk82Yj4DyvwjM1FL2R73zqidZhV3mvV14TmRJgApv1rZPE9dDBSg==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -6601,8 +6601,8 @@ packages: dev: false optional: true - /@ice/pack-binding-win32-x64-msvc@0.0.11: - resolution: {integrity: sha512-Ewsma3rd/p8FQUcbNuTH8EFmjvgbGHh9gtIcHlT8MyXXjOyV9lDpwDDqmzM0M3Re0FenOSeMDI+1LFy9/mNN3Q==} + /@ice/pack-binding-win32-x64-msvc@0.0.12: + resolution: {integrity: sha512-yjn2aGLLNDWLQGHt3Svl3JR6KtnEvt3rS052h/gl/dL1sVx1d0VqMZ6yWoDP1P3scJCA7O7Iu1rdBQnMtHFNYw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -6610,17 +6610,17 @@ packages: dev: false optional: true - /@ice/pack-binding@0.0.11: - resolution: {integrity: sha512-FEiJ42urDfiYHNAOb4/6Twcwd3KzUwi65qKFlATqCFZM3Fyh/sqwmcMDAvrM0vgJfCP11cmGBD1GsvbMUunP5Q==} + /@ice/pack-binding@0.0.12: + resolution: {integrity: sha512-09hX2T2nASifPqSSyscgUgquZcoIFGG8cn/3WeOaBRPoZ8d1UjmAetEgRWWzaGPCoOjY8Lo5tV8BGvQKyj91/Q==} engines: {node: '>= 10'} optionalDependencies: - '@ice/pack-binding-darwin-arm64': 0.0.11 - '@ice/pack-binding-darwin-universal': 0.0.11 - '@ice/pack-binding-darwin-x64': 0.0.11 - '@ice/pack-binding-linux-x64-gnu': 0.0.11 - '@ice/pack-binding-linux-x64-musl': 0.0.11 - '@ice/pack-binding-win32-arm64-msvc': 0.0.11 - '@ice/pack-binding-win32-x64-msvc': 0.0.11 + '@ice/pack-binding-darwin-arm64': 0.0.12 + '@ice/pack-binding-darwin-universal': 0.0.12 + '@ice/pack-binding-darwin-x64': 0.0.12 + '@ice/pack-binding-linux-x64-gnu': 0.0.12 + '@ice/pack-binding-linux-x64-musl': 0.0.12 + '@ice/pack-binding-win32-arm64-msvc': 0.0.12 + '@ice/pack-binding-win32-x64-msvc': 0.0.12 dev: false /@ice/pkg@1.5.5: @@ -7785,94 +7785,94 @@ packages: rollup: 2.79.1 dev: true - /@rspack/binding-darwin-arm64@0.5.4: - resolution: {integrity: sha512-MWTLMzrgWk5enKGfctVIhbU5WlpJbXpvUnHKzxSr4dclf+IeBIaXBEs1fwogrS87VdfWTOh+lndyzrozBnxMmQ==} + /@rspack/binding-darwin-arm64@0.5.7: + resolution: {integrity: sha512-zYTMILRyrON25MW7ifEhkZ6jL33mz8bAHTOhgR8yMpYVJjrKu60+s1qPa+t+GkaH7nNnVmzkTVGECCvaA75hJQ==} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /@rspack/binding-darwin-x64@0.5.4: - resolution: {integrity: sha512-+8kvYjN9IllQSSzTrKp74Cf2efFNJZNMk6PWoOeakk43+Z1BgMgzLJTs/1xIDFhzylvLSMYSLO8AhbMMX48TCw==} + /@rspack/binding-darwin-x64@0.5.7: + resolution: {integrity: sha512-4THSPWVKPMSSD/y3/TWZ5xlSeh1B33I+YnBu/Y3lDFcFrFPtc3ojIDHw3is6l2wcACX6Rro4RgN6zcUij7eEmQ==} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /@rspack/binding-linux-arm64-gnu@0.5.4: - resolution: {integrity: sha512-mXtRKCblBT+H1KPWUfeJt6gQFGoMt+lnhk2POcoCeS1AxnxcTFpnci4BC4Ro5zKS2QWSdGdUMtc5GKlBmgwxvg==} + /@rspack/binding-linux-arm64-gnu@0.5.7: + resolution: {integrity: sha512-JB9FAYWjYAeNCPFh0mQu3SZdFHiA+EY37z1AktLDl789SoEec2HPGkvvOs+OIET1pKWgjUGD4Z4Uq4P/r5JFNA==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rspack/binding-linux-arm64-musl@0.5.4: - resolution: {integrity: sha512-P96R8yLT4BKtwYCtomIJE4uIGAh+5I8qLbrTrGamj/6N1D79GgwORW6CllCEnVU9l/Tjkdd+yMJkT9zoACa9gQ==} + /@rspack/binding-linux-arm64-musl@0.5.7: + resolution: {integrity: sha512-3fNhPvA9Kj/L7rwr2Pj1bvxWBLBgqfkqSvt91iUxPbxgfTiSBQh0Tfb9+hkHv2VCTyNQI/vytkOH+4i4DNXCBw==} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /@rspack/binding-linux-x64-gnu@0.5.4: - resolution: {integrity: sha512-/EjM7CkALS7uUF0laVp+wtOICrX2sR5gy4liIYVHKDLu+b4PGRtEQvubrDxikkzPpOYRvF38R7OBMUOJBuBW7A==} + /@rspack/binding-linux-x64-gnu@0.5.7: + resolution: {integrity: sha512-y/GnXt1hhbKSqzBSy+ALWwievlejQhIIF8FPXL1kKFh60zl7DE+iYHSJ128jIJiph9dQkBnHw0ABJ5D+vbSqdA==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rspack/binding-linux-x64-musl@0.5.4: - resolution: {integrity: sha512-dMT9QW4IZ7IGzczsOmzdpGf84IzIecvitSwj7DnulRkxj3++IWLAo80+HDtgn+nPm+1gNVFb11wg5L9x+VjFXw==} + /@rspack/binding-linux-x64-musl@0.5.7: + resolution: {integrity: sha512-US/FUv6cvbxbe4nymINwer/EQTvGEgCaAIrvKuAP0yAfK0eyqIHYZj/zCBM2qOS69Mpc2FWVMC/ftRyCvAz/xw==} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /@rspack/binding-win32-arm64-msvc@0.5.4: - resolution: {integrity: sha512-SsnOqWRw5VQnbz/63wtKsoyj6lfUpQQZyFWfQAMsNt8suIauWI/kf3QLWL/vmBX5Q24Sq16Kl5cMIjxAIJQfiQ==} + /@rspack/binding-win32-arm64-msvc@0.5.7: + resolution: {integrity: sha512-g7NWXa5EGvh6j1VPXGOFaWuOVxdPYYLh3wpUl46Skrd6qFZKB2r+yNhuXo6lqezwYvbtHEDrmFOHF2S6epXO5g==} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /@rspack/binding-win32-ia32-msvc@0.5.4: - resolution: {integrity: sha512-xLlUHn712WhnWN40JeljQCiWBIRd/meMRKSEqTJJdZfNwozd4cZUbq5rxexX6HNjZvkwLACpATDotPVfCKPjbQ==} + /@rspack/binding-win32-ia32-msvc@0.5.7: + resolution: {integrity: sha512-5Udt4pYpPSd1wlbVKTdWzjha8oV+FQ/EXILHhoS9G7l9rbpqhMs6oIqAgEavQS3t6fKtQU837b+MSBNprudTtw==} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /@rspack/binding-win32-x64-msvc@0.5.4: - resolution: {integrity: sha512-33IBq3yuJTyUKhTGbPwP/kvSf58wpOCBdPvye+ExNSw0uEVwXMs2AqDWDnbBPtZjP8DVN/zu0EoeLhYk9fwkYg==} + /@rspack/binding-win32-x64-msvc@0.5.7: + resolution: {integrity: sha512-tB/SB27BBDVV0+GpEUHkl2uanCP4Jk/hlnbvl5u6lSGcIxCFm+da4OsyiGDRE24bSEdMc91dmyWVlx5425je+A==} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /@rspack/binding@0.5.4: - resolution: {integrity: sha512-WoAq+pkNAe4jetIwIoUbiqO4cLSvpll90GtpYHqaNS9r9n28l4LBQY/A15W0/XBZeoj0wvMkYEvEZtn64PULLw==} + /@rspack/binding@0.5.7: + resolution: {integrity: sha512-47MX6wNF1lP/LdShPVhbg689FX1W96Zji7QgbxhRhXmkpOKor7gdajhxqszFHxHYJtqNTLA9BSG38rpIGxJ+fw==} optionalDependencies: - '@rspack/binding-darwin-arm64': 0.5.4 - '@rspack/binding-darwin-x64': 0.5.4 - '@rspack/binding-linux-arm64-gnu': 0.5.4 - '@rspack/binding-linux-arm64-musl': 0.5.4 - '@rspack/binding-linux-x64-gnu': 0.5.4 - '@rspack/binding-linux-x64-musl': 0.5.4 - '@rspack/binding-win32-arm64-msvc': 0.5.4 - '@rspack/binding-win32-ia32-msvc': 0.5.4 - '@rspack/binding-win32-x64-msvc': 0.5.4 - dev: true - - /@rspack/core@0.5.4(patch_hash=cx7wc7uikmrb5dsrfcy5wrjzui)(@swc/helpers@0.5.1): - resolution: {integrity: sha512-3yxOllEC93gf4pNiLlgtzE8dPo0QV2naQY24gAPk+EoWlwpmR6p1r7ZdD53etFZPGB4hMm78J/zgwx8jy1TRsw==} + '@rspack/binding-darwin-arm64': 0.5.7 + '@rspack/binding-darwin-x64': 0.5.7 + '@rspack/binding-linux-arm64-gnu': 0.5.7 + '@rspack/binding-linux-arm64-musl': 0.5.7 + '@rspack/binding-linux-x64-gnu': 0.5.7 + '@rspack/binding-linux-x64-musl': 0.5.7 + '@rspack/binding-win32-arm64-msvc': 0.5.7 + '@rspack/binding-win32-ia32-msvc': 0.5.7 + '@rspack/binding-win32-x64-msvc': 0.5.7 + dev: true + + /@rspack/core@0.5.7(patch_hash=hydgitlae4ar2jrvgl5qp2f2um)(@swc/helpers@0.5.1): + resolution: {integrity: sha512-gUF0PcanPrC2cVfFA4e+qmG66X7FkEKlRbnaUfB4LKw9JQuwiMOXCAtrBdveDjB89KE/3cw/nuYVQwd106uqWA==} engines: {node: '>=16.0.0'} peerDependencies: '@swc/helpers': '>=0.5.1' @@ -7881,16 +7881,15 @@ packages: optional: true dependencies: '@module-federation/runtime-tools': 0.0.8 - '@rspack/binding': 0.5.4 + '@rspack/binding': 0.5.7 '@swc/helpers': 0.5.1 - browserslist: 4.22.1 + browserslist: 4.22.3 enhanced-resolve: 5.12.0 events: 3.3.0 graceful-fs: 4.2.10 json-parse-even-better-errors: 3.0.0 neo-async: 2.6.2 tapable: 2.2.1 - terminal-link: 2.1.1 watchpack: 2.4.0 webpack-sources: 3.2.3 zod: 3.22.3 @@ -7898,12 +7897,12 @@ packages: dev: true patched: true - /@rspack/dev-server@0.5.4(@rspack/core@0.5.4)(@types/express@4.17.17)(webpack@5.88.2): - resolution: {integrity: sha512-fwJGXCgv38paLkY7yIp3+nTxC/DQ3G2c7qh7UPyr4m3Jrb2X1YdATKE+JOIDd8++P8w/ug4d0Zj0xuwY89zFIA==} + /@rspack/dev-server@0.5.7(@rspack/core@0.5.7)(@types/express@4.17.17)(webpack@5.88.2): + resolution: {integrity: sha512-CqPZLRq7QCr6EQqYIBFeIeWemXh1TM2RPc3ZZ1Gap+6/KJuRTMIYv/Q3mSQqLET7dn+HQYSWPSoTciJmPu6zCw==} peerDependencies: '@rspack/core': '*' dependencies: - '@rspack/core': 0.5.4(patch_hash=cx7wc7uikmrb5dsrfcy5wrjzui)(@swc/helpers@0.5.1) + '@rspack/core': 0.5.7(patch_hash=hydgitlae4ar2jrvgl5qp2f2um)(@swc/helpers@0.5.1) chokidar: 3.5.3 connect-history-api-fallback: 2.0.0 express: 4.18.1 @@ -7922,8 +7921,8 @@ packages: - webpack-cli dev: true - /@rspack/plugin-react-refresh@0.5.4(react-refresh@0.14.0): - resolution: {integrity: sha512-neyCo1bBhTUriu2dSCu6FHQuILKDiKRokIy8B4V3hhequvW6F8EZ1rLcLoHfeikRIzC3ehJxOIuAj2sq6AiJMg==} + /@rspack/plugin-react-refresh@0.5.7(react-refresh@0.14.0): + resolution: {integrity: sha512-VDVzr0vkBpCeUL7m5PZK7OqB3M+sfSrlkt/1jxFM2sleaRmukxX9Pn+nIYopDbB47HkldotP/GeXCjUwfpAKug==} peerDependencies: react-refresh: '>=0.10.0 <1.0.0' peerDependenciesMeta: @@ -10614,7 +10613,6 @@ packages: electron-to-chromium: 1.4.656 node-releases: 2.0.14 update-browserslist-db: 1.0.13(browserslist@4.22.3) - dev: true /bs-logger@0.2.6: resolution: {integrity: sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==} @@ -10814,7 +10812,7 @@ packages: /caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} dependencies: - browserslist: 4.22.1 + browserslist: 4.22.3 caniuse-lite: 1.0.30001564 lodash.memoize: 4.1.2 lodash.uniq: 4.5.0 @@ -10827,7 +10825,6 @@ packages: /caniuse-lite@1.0.30001584: resolution: {integrity: sha512-LOz7CCQ9M1G7OjJOF9/mzmqmj3jE/7VOmrfw6Mgs0E8cjOsbRXQJHsPBfmBOXDskXKrHLyyW3n7kpDW/4BsfpQ==} - dev: true /caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} @@ -11398,7 +11395,7 @@ packages: /core-js-compat@3.29.0: resolution: {integrity: sha512-ScMn3uZNAFhK2DGoEfErguoiAHhV2Ju+oJo/jK08p7B3f3UhocUrCCkTvnZaiS+edl5nlIoiBXKcwMc6elv4KQ==} dependencies: - browserslist: 4.22.1 + browserslist: 4.22.3 /core-js-pure@3.29.0: resolution: {integrity: sha512-v94gUjN5UTe1n0yN/opTihJ8QBWD2O8i19RfTZR7foONPWArnjB96QA/wk5ozu1mm6ja3udQCzOzwQXTxi3xOQ==} @@ -12412,7 +12409,6 @@ packages: /electron-to-chromium@1.4.656: resolution: {integrity: sha512-9AQB5eFTHyR3Gvt2t/NwR0le2jBSUNwCnMbUCejFWHD+so4tH40/dRLgoE+jxlPeWS43XJewyvCv+I8LPMl49Q==} - dev: true /emittery@0.10.2: resolution: {integrity: sha512-aITqOwnLanpHLNXZJENbOgjUBeHocD+xsSJmNrjovKBW5HbSpW3d1pEls7GFQPUWXiwG9+0P4GtHfEqC/4M0Iw==} @@ -17157,7 +17153,6 @@ packages: /node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} - dev: true /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} @@ -17796,7 +17791,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.22.1 + browserslist: 4.22.3 caniuse-api: 3.0.0 colord: 2.9.3 postcss: 8.4.31 @@ -17808,7 +17803,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.22.1 + browserslist: 4.22.3 postcss: 8.4.31 postcss-value-parser: 4.2.0 @@ -18103,7 +18098,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.22.1 + browserslist: 4.22.3 caniuse-api: 3.0.0 cssnano-utils: 3.1.0(postcss@8.4.31) postcss: 8.4.31 @@ -18135,7 +18130,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.22.1 + browserslist: 4.22.3 cssnano-utils: 3.1.0(postcss@8.4.31) postcss: 8.4.31 postcss-value-parser: 4.2.0 @@ -18292,7 +18287,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.22.1 + browserslist: 4.22.3 postcss: 8.4.31 postcss-value-parser: 4.2.0 @@ -18447,7 +18442,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.22.1 + browserslist: 4.22.3 caniuse-api: 3.0.0 postcss: 8.4.31 @@ -21553,7 +21548,7 @@ packages: peerDependencies: postcss: ^8.2.15 dependencies: - browserslist: 4.22.1 + browserslist: 4.22.3 postcss: 8.4.31 postcss-selector-parser: 6.0.11 @@ -22689,7 +22684,6 @@ packages: browserslist: 4.22.3 escalade: 3.1.1 picocolors: 1.0.0 - dev: true /update-notifier@5.1.0: resolution: {integrity: sha512-ItnICHbeMh9GqUy31hFPrD1kcuZ3rpxDZbf4KUDavXwS0bW5m7SLbDQpGX3UYr072cbrF5hFUs3r5tUsPwjfHw==} From 25c7584326bd039c6d6868582f8162b8260f819a Mon Sep 17 00:00:00 2001 From: Homyee King Date: Wed, 20 Mar 2024 14:44:21 +0800 Subject: [PATCH 07/10] feat: dynamic API (#6831) * chore: save * feat: basic dynamic * feat: export from ice/runtime * test: with-dynamic * test(with-dynamic): name export * feat: use useMounted * chore: cmt * chore: up lock file * chore: use universal-env * fix: ci * Revert "chore: use universal-env" This reverts commit 98f5dff99f17d0cf3b65dd5c2cceea07f4806a3d. * chore: optimize logic --- examples/with-dynamic/.browserslistrc | 1 + examples/with-dynamic/ice.config.mts | 5 + examples/with-dynamic/package.json | 23 ++++ examples/with-dynamic/src/app.tsx | 6 ++ .../with-dynamic/src/components/nonssr.tsx | 6 ++ .../with-dynamic/src/components/normal.tsx | 7 ++ examples/with-dynamic/src/document.tsx | 22 ++++ .../src/pages/nonssr/no-ssr-fallback.tsx | 10 ++ .../src/pages/nonssr/no-ssr-no-fallback.tsx | 9 ++ .../src/pages/nonssr/ssr-no-fallback.tsx | 7 ++ .../src/pages/nonssr/without-dynamic.tsx | 5 + .../src/pages/normal/bare-import.tsx | 9 ++ .../with-dynamic/src/pages/normal/basic.tsx | 9 ++ .../src/pages/normal/name-export.tsx | 13 +++ examples/with-dynamic/src/typings.d.ts | 1 + examples/with-dynamic/tsconfig.json | 44 ++++++++ packages/ice/src/constant.ts | 1 + packages/runtime/src/dynamic.tsx | 55 ++++++++++ packages/runtime/src/index.ts | 3 +- pnpm-lock.yaml | 25 +++++ tests/integration/with-dynamic.test.ts | 100 ++++++++++++++++++ vitest.config.ts | 1 + 22 files changed, 361 insertions(+), 1 deletion(-) create mode 100644 examples/with-dynamic/.browserslistrc create mode 100644 examples/with-dynamic/ice.config.mts create mode 100644 examples/with-dynamic/package.json create mode 100644 examples/with-dynamic/src/app.tsx create mode 100644 examples/with-dynamic/src/components/nonssr.tsx create mode 100644 examples/with-dynamic/src/components/normal.tsx create mode 100644 examples/with-dynamic/src/document.tsx create mode 100644 examples/with-dynamic/src/pages/nonssr/no-ssr-fallback.tsx create mode 100644 examples/with-dynamic/src/pages/nonssr/no-ssr-no-fallback.tsx create mode 100644 examples/with-dynamic/src/pages/nonssr/ssr-no-fallback.tsx create mode 100644 examples/with-dynamic/src/pages/nonssr/without-dynamic.tsx create mode 100644 examples/with-dynamic/src/pages/normal/bare-import.tsx create mode 100644 examples/with-dynamic/src/pages/normal/basic.tsx create mode 100644 examples/with-dynamic/src/pages/normal/name-export.tsx create mode 100644 examples/with-dynamic/src/typings.d.ts create mode 100644 examples/with-dynamic/tsconfig.json create mode 100644 packages/runtime/src/dynamic.tsx create mode 100644 tests/integration/with-dynamic.test.ts diff --git a/examples/with-dynamic/.browserslistrc b/examples/with-dynamic/.browserslistrc new file mode 100644 index 0000000000..7637baddc3 --- /dev/null +++ b/examples/with-dynamic/.browserslistrc @@ -0,0 +1 @@ +chrome 55 \ No newline at end of file diff --git a/examples/with-dynamic/ice.config.mts b/examples/with-dynamic/ice.config.mts new file mode 100644 index 0000000000..a1def9fd76 --- /dev/null +++ b/examples/with-dynamic/ice.config.mts @@ -0,0 +1,5 @@ +import { defineConfig } from '@ice/app'; + +export default defineConfig(() => ({ + ssr: true, +})); diff --git a/examples/with-dynamic/package.json b/examples/with-dynamic/package.json new file mode 100644 index 0000000000..e254ad7984 --- /dev/null +++ b/examples/with-dynamic/package.json @@ -0,0 +1,23 @@ +{ + "name": "@examples/with-dynamic", + "private": true, + "version": "1.0.0", + "scripts": { + "start": "ice start", + "build": "ice build" + }, + "description": "ICE example with dynamic", + "author": "ICE Team", + "license": "MIT", + "dependencies": { + "@ice/app": "workspace:*", + "@ice/runtime": "workspace:*", + "react": "^18.2.0", + "react-dom": "^18.2.0", + "tslib": "^2.4.0" + }, + "devDependencies": { + "@types/react": "^18.0.17", + "@types/react-dom": "^18.0.6" + } +} \ No newline at end of file diff --git a/examples/with-dynamic/src/app.tsx b/examples/with-dynamic/src/app.tsx new file mode 100644 index 0000000000..74015d9cf4 --- /dev/null +++ b/examples/with-dynamic/src/app.tsx @@ -0,0 +1,6 @@ +export default { + app: { + rootId: 'app', + type: 'browser', + }, +}; diff --git a/examples/with-dynamic/src/components/nonssr.tsx b/examples/with-dynamic/src/components/nonssr.tsx new file mode 100644 index 0000000000..08637b1df9 --- /dev/null +++ b/examples/with-dynamic/src/components/nonssr.tsx @@ -0,0 +1,6 @@ +export default (props) => { + window.addEventListener('load', () => { + console.log('load'); + }); + return
{props.text}
; +}; diff --git a/examples/with-dynamic/src/components/normal.tsx b/examples/with-dynamic/src/components/normal.tsx new file mode 100644 index 0000000000..0f1d723444 --- /dev/null +++ b/examples/with-dynamic/src/components/normal.tsx @@ -0,0 +1,7 @@ +export default () => { + return
normal text
; +}; + +export function NameExportComp() { + return
name exported
; +} diff --git a/examples/with-dynamic/src/document.tsx b/examples/with-dynamic/src/document.tsx new file mode 100644 index 0000000000..61e35a7ec2 --- /dev/null +++ b/examples/with-dynamic/src/document.tsx @@ -0,0 +1,22 @@ +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +function Document() { + return ( + + + + + + + + <Links /> + </head> + <body> + <Main /> + <Scripts /> + </body> + </html> + ); +} + +export default Document; diff --git a/examples/with-dynamic/src/pages/nonssr/no-ssr-fallback.tsx b/examples/with-dynamic/src/pages/nonssr/no-ssr-fallback.tsx new file mode 100644 index 0000000000..c63a950ff7 --- /dev/null +++ b/examples/with-dynamic/src/pages/nonssr/no-ssr-fallback.tsx @@ -0,0 +1,10 @@ +import { dynamic } from '@ice/runtime'; + +const NonSSR = dynamic(() => import('@/components/nonssr'), { + ssr: false, + fallback: () => <div>fallback</div>, +}); + +export default () => { + return <NonSSR text={'hello world'} />; +}; diff --git a/examples/with-dynamic/src/pages/nonssr/no-ssr-no-fallback.tsx b/examples/with-dynamic/src/pages/nonssr/no-ssr-no-fallback.tsx new file mode 100644 index 0000000000..416bf4f4c5 --- /dev/null +++ b/examples/with-dynamic/src/pages/nonssr/no-ssr-no-fallback.tsx @@ -0,0 +1,9 @@ +import { dynamic } from '@ice/runtime'; + +const NonSSR = dynamic(() => import('@/components/nonssr'), { + ssr: false, +}); + +export default () => { + return <NonSSR text={'hello world'} />; +}; diff --git a/examples/with-dynamic/src/pages/nonssr/ssr-no-fallback.tsx b/examples/with-dynamic/src/pages/nonssr/ssr-no-fallback.tsx new file mode 100644 index 0000000000..e6fcc6dcdf --- /dev/null +++ b/examples/with-dynamic/src/pages/nonssr/ssr-no-fallback.tsx @@ -0,0 +1,7 @@ +import { dynamic } from '@ice/runtime'; + +const NonSSR = dynamic(() => import('@/components/nonssr')); + +export default () => { + return <NonSSR text={'hello world'} />; +}; diff --git a/examples/with-dynamic/src/pages/nonssr/without-dynamic.tsx b/examples/with-dynamic/src/pages/nonssr/without-dynamic.tsx new file mode 100644 index 0000000000..0a9c79c325 --- /dev/null +++ b/examples/with-dynamic/src/pages/nonssr/without-dynamic.tsx @@ -0,0 +1,5 @@ +import NonSsr from '@/components/nonssr'; + +export default () => { + return <NonSsr text={'without dynamic'} />; +}; diff --git a/examples/with-dynamic/src/pages/normal/bare-import.tsx b/examples/with-dynamic/src/pages/normal/bare-import.tsx new file mode 100644 index 0000000000..58e2010194 --- /dev/null +++ b/examples/with-dynamic/src/pages/normal/bare-import.tsx @@ -0,0 +1,9 @@ +import { dynamic } from '@ice/runtime'; + +const Normal = dynamic(import('../../components/normal'), { + fallback: () => <div>bare import fallback</div>, +}); + +export default () => { + return <Normal />; +}; diff --git a/examples/with-dynamic/src/pages/normal/basic.tsx b/examples/with-dynamic/src/pages/normal/basic.tsx new file mode 100644 index 0000000000..03292de0fd --- /dev/null +++ b/examples/with-dynamic/src/pages/normal/basic.tsx @@ -0,0 +1,9 @@ +import { dynamic } from '@ice/runtime'; + +const Normal = dynamic(() => import('../../components/normal'), { + fallback: () => <div>normal fallback</div>, +}); + +export default () => { + return <Normal />; +}; diff --git a/examples/with-dynamic/src/pages/normal/name-export.tsx b/examples/with-dynamic/src/pages/normal/name-export.tsx new file mode 100644 index 0000000000..cfdeb4335a --- /dev/null +++ b/examples/with-dynamic/src/pages/normal/name-export.tsx @@ -0,0 +1,13 @@ +import { dynamic } from '@ice/runtime'; + +const Normal = dynamic( + import('../../components/normal').then((mod) => { + return { + default: mod.NameExportComp, + }; + }), +); + +export default () => { + return <Normal />; +}; diff --git a/examples/with-dynamic/src/typings.d.ts b/examples/with-dynamic/src/typings.d.ts new file mode 100644 index 0000000000..1f6ba4ffa6 --- /dev/null +++ b/examples/with-dynamic/src/typings.d.ts @@ -0,0 +1 @@ +/// <reference types="@ice/app/types" /> diff --git a/examples/with-dynamic/tsconfig.json b/examples/with-dynamic/tsconfig.json new file mode 100644 index 0000000000..895d41392f --- /dev/null +++ b/examples/with-dynamic/tsconfig.json @@ -0,0 +1,44 @@ +{ + "compileOnSave": false, + "buildOnSave": false, + "compilerOptions": { + "baseUrl": ".", + "outDir": "build", + "module": "esnext", + "target": "es6", + "jsx": "react-jsx", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "lib": [ + "es6", + "dom" + ], + "sourceMap": true, + "allowJs": true, + "rootDir": "./", + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": false, + "importHelpers": true, + "strictNullChecks": true, + "noUnusedLocals": true, + "skipLibCheck": true, + "paths": { + "@/*": [ + "./src/*" + ], + "ice": [ + ".ice" + ] + } + }, + "include": [ + "src", + ".ice", "src/pages/with-dynamic/.tsx", + ], + "exclude": [ + "build", + "public" + ] +} \ No newline at end of file diff --git a/packages/ice/src/constant.ts b/packages/ice/src/constant.ts index bf7a6969f2..02a1d54684 100644 --- a/packages/ice/src/constant.ts +++ b/packages/ice/src/constant.ts @@ -69,6 +69,7 @@ export const RUNTIME_EXPORTS = [ 'Await', 'usePageLifecycle', 'unstable_useDocumentData', + 'dynamic', ], alias: { usePublicAppContext: 'useAppContext', diff --git a/packages/runtime/src/dynamic.tsx b/packages/runtime/src/dynamic.tsx new file mode 100644 index 0000000000..77de22cb15 --- /dev/null +++ b/packages/runtime/src/dynamic.tsx @@ -0,0 +1,55 @@ +import type { ReactNode } from 'react'; +import React, { Suspense, lazy } from 'react'; +import useMounted from './useMounted.js'; + +const isServer = import.meta.renderer === 'server'; + +type ComponentModule<P = {}> = { default: React.ComponentType<P> }; + +export type LoaderComponent<P = {}> = Promise<React.ComponentType<P> | ComponentModule<P>>; + +export type Loader<P = {}> = (() => LoaderComponent<P>) | LoaderComponent<P>; + +export interface DynamicOptions { + /** @default true */ + ssr?: boolean; + /** the fallback UI to render before the actual is loaded */ + fallback?: () => ReactNode; +} + +// Normalize loader to return the module as form { default: Component } for `React.lazy`. +function convertModule<P>(mod: React.ComponentType<P> | ComponentModule<P>) { + return { default: (mod as ComponentModule<P>)?.default || mod }; +} + +const DefaultFallback = () => null; + +export function dynamic<P = {}>(loader: Loader<P>, option?: DynamicOptions) { + const { ssr = true, fallback = DefaultFallback } = option || {}; + let realLoader; + // convert dynamic(import('xxx')) to dynamic(() => import('xxx')) + if (loader instanceof Promise) { + realLoader = () => loader; + } else if (typeof loader === 'function') { + realLoader = loader; + } + if (!realLoader) return DefaultFallback; + const Fallback = fallback; + + if (!ssr && isServer) { + return () => <Fallback />; + } + + const LazyComp = lazy(() => realLoader().then(convertModule)); + return (props) => { + const hasMounted = useMounted(); + + return ssr || hasMounted ? ( + <Suspense fallback={<Fallback />}> + <LazyComp {...props} /> + </Suspense> + ) : ( + <Fallback /> + ); + }; +} diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index c62c946ed6..f5306cc11c 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -50,7 +50,7 @@ import useMounted from './useMounted.js'; import usePageLifecycle from './usePageLifecycle.js'; import { withSuspense, useSuspenseData } from './Suspense.js'; import { createRouteLoader, WrapRouteComponent, RouteErrorComponent, Await } from './routes.js'; - +import { dynamic } from './dynamic.js'; function useAppContext() { console.warn('import { useAppContext } from \'@ice/runtime\'; is deprecated, please use import { useAppContext } from \'ice\'; instead.'); return useInternalAppContext(); @@ -117,6 +117,7 @@ export { callDataLoader, getRequestContext, history, + dynamic, useActive, KeepAliveOutlet, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e5db4cdadc..9ceb044d92 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -792,6 +792,31 @@ importers: specifier: ^18.0.6 version: 18.0.11 + examples/with-dynamic: + dependencies: + '@ice/app': + specifier: workspace:* + version: link:../../packages/ice + '@ice/runtime': + specifier: workspace:* + version: link:../../packages/runtime + react: + specifier: ^18.2.0 + version: 18.2.0 + react-dom: + specifier: ^18.2.0 + version: 18.2.0(react@18.2.0) + tslib: + specifier: ^2.4.0 + version: 2.5.0 + devDependencies: + '@types/react': + specifier: ^18.0.17 + version: 18.0.34 + '@types/react-dom': + specifier: ^18.0.6 + version: 18.0.11 + examples/with-entry-type: dependencies: '@ice/app': diff --git a/tests/integration/with-dynamic.test.ts b/tests/integration/with-dynamic.test.ts new file mode 100644 index 0000000000..2aff930b90 --- /dev/null +++ b/tests/integration/with-dynamic.test.ts @@ -0,0 +1,100 @@ +import * as path from 'path'; +import * as fs from 'fs'; +import { fileURLToPath } from 'url'; +import { expect, test, describe, afterAll, beforeAll } from 'vitest'; +import { buildFixture, setupBrowser } from '../utils/build'; +import type { Page } from '../utils/browser'; +import type Browser from '../utils/browser'; + +// @ts-ignore +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +const example = 'with-dynamic'; + +describe(`build ${example}`, () => { + let page: Page; + let browser: Browser; + + beforeAll(async () => { + await buildFixture(example); + const res = await setupBrowser({ example }); + + page = res.page; + browser = res.browser; + }); + + describe('normal case', () => { + test('basic case', async () => { + const htmlPath = '/normal/basic.html'; + await page.push(htmlPath); + const htmlContent = fs.readFileSync(path.join(__dirname, `../../examples/${example}/build${htmlPath}`), 'utf-8'); + + expect(htmlContent.includes('"renderMode":"SSG"')).toBe(true); + expect(htmlContent.includes('<!--$?--><template id="B:0"></template><div>normal fallback</div>')).toBe(true); + expect(htmlContent.includes('<div hidden id="S:0"><div>normal text</div>')).toBe(true); + }); + + test('should support call w/ a bare import', async () => { + const htmlPath = '/normal/bare-import.html'; + await page.push(htmlPath); + const htmlContent = fs.readFileSync(path.join(__dirname, `../../examples/${example}/build${htmlPath}`), 'utf-8'); + + expect(htmlContent.includes('"renderMode":"SSG"')).toBe(true); + expect(htmlContent.includes('<!--$?--><template id="B:0"></template><div>bare import fallback</div>')).toBe(true); + expect(htmlContent.includes('<div hidden id="S:0"><div>normal text</div>')).toBe(true); + }); + + test('should support name export', async () => { + const htmlPath = '/normal/name-export.html'; + await page.push(htmlPath); + const htmlContent = fs.readFileSync(path.join(__dirname, `../../examples/${example}/build${htmlPath}`), 'utf-8'); + + expect(htmlContent.includes('"renderMode":"SSG"')).toBe(true); + expect(htmlContent.includes('<div hidden id="S:0"><div>name exported</div></div>')).toBe(true); + }); + }); + + describe('non-ssr pkg case', () => { + test('should downgrade when ssr w/o fallback', async () => { + const htmlPath = '/nonssr/ssr-no-fallback.html'; + await page.push(htmlPath); + const htmlContent = fs.readFileSync(path.join(__dirname, `../../examples/${example}/build${htmlPath}`), 'utf-8'); + + expect(await page.$$text('#app')).toStrictEqual(['']); + expect(htmlContent.includes('"renderMode":"CSR"')).toBe(true); + expect(htmlContent.includes('"downgrade":true')).toBe(true); + }); + + test('should not downgrade when no ssr no fallback', async () => { + const htmlPath = '/nonssr/no-ssr-no-fallback.html'; + await page.push(htmlPath); + const htmlContent = fs.readFileSync(path.join(__dirname, `../../examples/${example}/build${htmlPath}`), 'utf-8'); + expect(await page.$$text('#app')).toStrictEqual(['']); + expect(htmlContent.includes('"renderMode":"SSG"')).toBe(true); + expect(htmlContent.includes('"downgrade":true')).toBe(false); + }); + + test('should not downgrade and display fallback when no ssr with fallback', async () => { + const htmlPath = '/nonssr/no-ssr-fallback.html'; + await page.push(htmlPath); + const htmlContent = fs.readFileSync(path.join(__dirname, `../../examples/${example}/build${htmlPath}`), 'utf-8'); + expect(await page.$$text('#app')).toStrictEqual(['fallback']); + expect(htmlContent.includes('"renderMode":"SSG"')).toBe(true); + expect(htmlContent.includes('"downgrade":true')).toBe(false); + }); + + test('should downgrade w/o using dynamic', async () => { + const htmlPath = '/nonssr/without-dynamic.html'; + await page.push(htmlPath); + const htmlContent = fs.readFileSync(path.join(__dirname, `../../examples/${example}/build${htmlPath}`), 'utf-8'); + + expect(await page.$$text('#app')).toStrictEqual(['']); + expect(htmlContent.includes('"renderMode":"CSR"')).toBe(true); + expect(htmlContent.includes('"downgrade":true')).toBe(true); + }); + }); + + afterAll(async () => { + await browser.close(); + }); +}); diff --git a/vitest.config.ts b/vitest.config.ts index b82be6202b..388f195e29 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -12,6 +12,7 @@ export default defineConfig({ }, test: { testTimeout: 120000, + hookTimeout: 120000, // To avoid error `Segmentation fault (core dumped)` in CI environment, disable threads // ref: https://github.com/vitest-dev/vitest/issues/317 threads: false, From a7c76b623aa6477324f446f69f5ac0e4a363c2c9 Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Wed, 20 Mar 2024 15:20:49 +0800 Subject: [PATCH 08/10] chore: add changeset (#6835) --- .changeset/gold-walls-explode.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/gold-walls-explode.md diff --git a/.changeset/gold-walls-explode.md b/.changeset/gold-walls-explode.md new file mode 100644 index 0000000000..4b1bfc22ee --- /dev/null +++ b/.changeset/gold-walls-explode.md @@ -0,0 +1,5 @@ +--- +'@ice/runtime': patch +--- + +feat: support API dynamic to allow import component in different scenario From a8a86d8b9c77476e5120e324067b1b2f45e2118f Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Wed, 20 Mar 2024 16:06:58 +0800 Subject: [PATCH 09/10] docs: update api document (#6836) --- .../docs/guide/advanced/integrate-from-rax.md | 11 --- website/docs/guide/basic/api.md | 85 ++++++++++--------- website/docs/guide/basic/app.md | 8 -- website/docs/guide/basic/config.md | 67 ++++++--------- website/docs/guide/basic/document.md | 6 +- website/docs/guide/basic/mock.md | 4 - 6 files changed, 71 insertions(+), 110 deletions(-) diff --git a/website/docs/guide/advanced/integrate-from-rax.md b/website/docs/guide/advanced/integrate-from-rax.md index 1b448e9e89..9acca2dd8c 100644 --- a/website/docs/guide/advanced/integrate-from-rax.md +++ b/website/docs/guide/advanced/integrate-from-rax.md @@ -5,17 +5,6 @@ order: 0901 本文档面向的是使用 Rax App 的开发者,提供迁移到 ice.js 的方式。React 的社区生态显著优于 Rax,切换到 React 之后可以享受到更多的 React 生态,复用复杂场景(富文本、脑图等)社区生态可以大幅度降低成本。 -:::caution -对于 Rax 小程序的用户,如果你没有使用到以下与原生小程序结合较为紧密的能力,则可以正常参考本文档进行迁移。 - -- 引入原生 app.js、原生页面、原生自定义组件、小程序插件 -- 引入 Rax 编译时组件 -- 注册页面生命周期及事件 -- 分包加载 - -如果使用到以上能力,则需要参考 ice.js 文档进行相应能力的迁移。 -::: - ## ice.js 与 Rax App 的差异 ice.js 和 Rax App 都是应用研发框架,它们默认使用的 UI Framework 不同,前者使用 React,而后者使用 rax.js。但是在 ice.js 3.x 中,你可以使用 [Rax 兼容模式](./rax-compat.md)来运行 Rax 组件。 diff --git a/website/docs/guide/basic/api.md b/website/docs/guide/basic/api.md index 4e598f2b82..833b841cc6 100644 --- a/website/docs/guide/basic/api.md +++ b/website/docs/guide/basic/api.md @@ -55,10 +55,6 @@ export function historyPush (link: string) { ### useParams -:::caution -小程序端不支持该 API。 -::: - useParams 函数返回动态路由的匹配参数信息。 ```tsx @@ -79,11 +75,6 @@ export default function Home() { ### useSearchParams -:::caution -小程序端会返回当前页面 `Page.onLoad` 生命周期返回的 query 参数。 -同时小程序端不支持修改 query string,即调用该 API 返回的 `setSearchParams` 不会生效。 -::: - useSearchParams 用于读取和修改当前 URL 的 query string。 ```tsx @@ -109,10 +100,6 @@ export default function Home() { ### useNavigate -:::caution -小程序端不支持该 API。可通过 Link 组件或 history 或小程序原生 API 进行跳转。 -::: - useNavigate 函数返回一个可以控制跳转的函数,用于组件内部控制路径跳转 ```tsx @@ -134,10 +121,6 @@ export default function Home() { ### useLocation -:::caution -小程序端不支持该 API。 -::: - useLocation 返回当前 location 信息。 ```tsx @@ -217,10 +200,6 @@ export const pageConfig = definePageConfig(() => ({ ### useMounted -:::caution -小程序端不支持该 API。 -::: - 该方法会在 React Hydrate 完成后返回 `true`,一般在开启 SSR/SSG 的应用中,用于控制在不同端中渲染不同的组件。 :::caution @@ -270,10 +249,6 @@ function Document() { ### `<ClientOnly />` -:::caution -小程序端不支持该组件。 -::: - `<ClientOnly />` 组件只允许在 React Hydrate 完成后在 Client 端中渲染组件。 :::tip @@ -315,20 +290,57 @@ export function Home () { }; ``` -### `<KeepAliveOutlet />` -:::caution -小程序端不支持该组件。 -::: +### dynamic + +`dynamic` API 是用于动态加载组件的 API,用于按需加载组件,并且通过参数配置可以控制组件在 Node 服务下的加载执行行为。 + +基础使用方式: + +```tsx +import { dynamic } from 'ice'; + +const ComponentA = dynamic(() => import('../components/A')); +const ComponentB = dynamic(() => import('../components/B')); +const ComponentC = dynamic(() => import('../components/C'), { ssr: false }); + +export default function Home({ show }) { + return ( + <> + {/* 渲染组件时直接加载,ComponentA 代码将拆分到额外的 bundle 中 */} + <ComponentA /> + {/* 仅在 show 为 true 时,加载 ComponentB,表现同 dynamic import */} + {show && <ComponentB />} + {/* 不会在 Node 服务端加载渲染,仅在浏览器端渲染,对于组件内容依赖 window 等 client 端变量的组件可以快速兼容*/} + <ComponentC /> + </> + ); +} +``` + +使用 fallback 方式: + +```tsx +import { dynamic } from 'ice'; + +const ComponentA = dynamic(() => import('../components/A'), { fallback: <div>loading...</div> }); + +export default function Home({ show }) { + return ( + <> + {/* 在 ComponentA 代码加载过程中将显示 fallback 内容 */} + <ComponentA /> + </> + ); +} +``` + +### `<KeepAliveOutlet />` 缓存所有路由组件的状态。详细使用方式参考 [Keep Alive 文档](../advanced/keep-alive/#缓存路由组件)。 ### `<Link />` -:::info -在小程序端 Link 组件底层为原生 `navigator` 组件。 -::: - `<Link>` 是 React 组件,用于渲染带路由跳转功能的 `<a>` 元素。 ```tsx @@ -348,10 +360,6 @@ function Home() { ### `<Outlet />` -:::caution -小程序端不支持该组件。 -::: - `<Outlet>` 用于渲染父路由中渲染子路由,通常出现在 `layout.tsx` Layout 组件中。 ```tsx title="src/layout.tsx" @@ -396,8 +404,5 @@ import type { RouteConfig } from 'ice'; ### Document 组件 -:::caution -小程序端不支持该组件。 -::: `Meta`、`Title`、`Links`、`Scripts` 和 `Main` 组件仅支持在 `src/document.tsx` 中使用,使用场景参考 [Document 文档](./document) diff --git a/website/docs/guide/basic/app.md b/website/docs/guide/basic/app.md index 017b7ce00f..2e4b0b4bd8 100644 --- a/website/docs/guide/basic/app.md +++ b/website/docs/guide/basic/app.md @@ -34,10 +34,6 @@ export default defineAppConfig(() => ({ - 类型:`string` - 默认值:`ice-container` -:::tip -小程序端不支持修改 rootId。 -::: - #### `strict` 是否开启 React 的严格模式 (React.StrictMode) @@ -54,10 +50,6 @@ export default defineAppConfig(() => ({ ### router -:::tip -小程序端不支持 `router` 配置。关于小程序的 `router` 配置参考[小程序开发-路由](../miniapp/router) -::: - #### `type` 路由类型 diff --git a/website/docs/guide/basic/config.md b/website/docs/guide/basic/config.md index 271cccdf94..25ad5ed6fa 100644 --- a/website/docs/guide/basic/config.md +++ b/website/docs/guide/basic/config.md @@ -57,10 +57,6 @@ export default defineConfig(() => ({ ### crossOriginLoading -:::caution -小程序端不支持该配置。 -::: - - 类型:`false | 'anonymous' | 'use-credentials'` - 默认值:`false` @@ -121,10 +117,6 @@ console.log(AGE); ### publicPath -:::caution -小程序端不支持该配置。 -::: - - 类型:`string` - 默认值:`/` @@ -139,10 +131,6 @@ console.log(AGE); ### hash -:::caution -小程序端不支持该配置。 -::: - - 类型:`boolean | string` - 默认值:`false` @@ -158,10 +146,6 @@ export default defineConfig(() => ({ ### externals -:::caution -小程序端不支持该配置。 -::: - - 类型:`Record<string, string>` - 默认值:`{}` @@ -208,10 +192,6 @@ export default Document; ### proxy -:::caution -小程序端不支持该配置。 -::: - - 类型:`object` - 默认值:`{}` @@ -402,10 +382,6 @@ export default defineConfig(() => ({ ### ssr -:::caution -小程序端不支持该配置。 -::: - - 类型:`boolean` - 默认值:`false` @@ -413,10 +389,6 @@ export default defineConfig(() => ({ ### ssg -:::caution -小程序端不支持该配置。 -::: - - 类型:`boolean` - 默认值:`true` @@ -424,10 +396,6 @@ export default defineConfig(() => ({ ### server -:::caution -小程序端不支持该配置。 -::: - - 类型:`{ format: 'esm' | 'cjs'; bundle: boolean; ignores: IgnorePattern[]; externals: string[]; onDemand: boolean; }` - 默认值:`{ format: 'esm', bundle: false, ignores: [], externals: [], onDemand: false }` @@ -491,10 +459,6 @@ export default defineConfig(() => ({ ### routes -:::caution -小程序端不支持该配置。 -::: - - 类型:`{ ignoreFiles: string[]; defineRoutes: (route: DefineRouteFunction) => void }` - 默认值:`{}` @@ -592,8 +556,7 @@ export default defineConfig({ ### splitChunks @deprecated :::caution -不再建议使用,能力由 codeSplitting 替代。 -小程序端不支持该配置。 +不再建议使用,能力由 codeSplitting 替代 ::: 默认会根据模块体积自动拆分 chunks,有可能会出现多个 bundle。如果不希望打包产物出现过多 bundle ,可设置成 `false`。 @@ -639,10 +602,6 @@ ice.js 内置了大量 ES 语法支持,便于开发者进行编码。对于 [p ### mock -:::caution -小程序端不支持该配置。 -::: - - 类型:`{ exclude: string[] }` - 默认值:`{}` @@ -731,4 +690,28 @@ export default defineConfig(() => ({ })); ``` +### optimization + +- 类型:`{ disableRouter: boolean; optimizePackageImport: boolean | string[] }` +- 默认值:`{}` + +框架提供内置的优化能力,针对不同场景提供优化策略: +- `disableRouter`:默认为 `false`,如果希望关闭路由能力,可以设置为 `true`。主要应用不存在依赖路由能力的场景,比如不存在 SPA 页面跳转。 +- `optimizePackageImport`:默认为 `false`,开启后框架默认会对已知三方依赖进行按需加载,项目的构建体验将进一步提升,内置三方依赖列表参考[代码](https://github.com/alibaba/ice/blob/1989fc18fa26230e91322e225dd20633d268a26b/packages/ice/src/config.ts#L364-L421)。 + + +参考配置: +```js +import { defineConfig } from '@ice/app'; + +export default defineConfig(() => ({ + optimization: { + disableRouter: true, + // optimizePackageImport 配置为 true 则使用内置的三方依赖列表,如果配置为数组则会在内置列表基础上追加 + optimizePackageImport: ['@ice/components'], + }, +})); +``` + + > 如有定制需求欢迎👏 PR 或反馈:<https://github.com/alibaba/ice/issues> diff --git a/website/docs/guide/basic/document.md b/website/docs/guide/basic/document.md index 1a5ef8a576..d21ddb8dd9 100644 --- a/website/docs/guide/basic/document.md +++ b/website/docs/guide/basic/document.md @@ -3,10 +3,6 @@ title: 定制 HTML order: 12 --- -:::tip -小程序端不支持该能力。 -::: - ice.js 使用 JSX 维护页面的 HTML 模板结构,其入口位于 `src/document.tsx`。 ## 初始模板 @@ -223,4 +219,4 @@ function Document() { </html> ); } -``` \ No newline at end of file +``` diff --git a/website/docs/guide/basic/mock.md b/website/docs/guide/basic/mock.md index 6e5ea8e431..504b4388c3 100644 --- a/website/docs/guide/basic/mock.md +++ b/website/docs/guide/basic/mock.md @@ -3,10 +3,6 @@ title: 数据模拟 Mock order: 7 --- -:::tip -小程序端不支持该能力。 -::: - 在前后端分离的开发中,Mock 数据是前端开发中很重要的一个环节,前端可以不必强依赖后端接口,只需要约定好对应的数据接口,前端可以通过 Mock 模拟数据先行开发,在后端接口开发完成后,只需要切换对应的接口地址即可,可以保证项目的同步开发。 ice.js 提供了开箱即用的 Mock 方案,支持 CRUD 等操作,在启动本地调试时会自动启用 Mock 服务。 From 277518dd7f5dfc1677a82090e55797deb039c936 Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Wed, 20 Mar 2024 16:20:41 +0800 Subject: [PATCH 10/10] chore: update versions (#6826) --- .changeset/brave-items-cover.md | 5 ----- .changeset/famous-roses-hide.md | 5 ----- .changeset/gold-walls-explode.md | 5 ----- .changeset/good-pans-joke.md | 7 ------- .changeset/khaki-parrots-invite.md | 9 --------- .changeset/metal-turtles-design.md | 5 ----- .changeset/olive-wolves-dress.md | 5 ----- packages/bundles/CHANGELOG.md | 7 +++++++ packages/bundles/package.json | 2 +- packages/ice/CHANGELOG.md | 18 ++++++++++++++++++ packages/ice/package.json | 12 ++++++------ packages/plugin-i18n/package.json | 4 ++-- packages/rax-compat/CHANGELOG.md | 6 ++++++ packages/rax-compat/package.json | 2 +- packages/rspack-config/CHANGELOG.md | 11 +++++++++++ packages/rspack-config/package.json | 6 +++--- packages/runtime/CHANGELOG.md | 9 +++++++++ packages/runtime/package.json | 2 +- packages/shared-config/CHANGELOG.md | 9 +++++++++ packages/shared-config/package.json | 4 ++-- packages/webpack-config/CHANGELOG.md | 9 +++++++++ packages/webpack-config/package.json | 6 +++--- pnpm-lock.yaml | 20 ++++++++++---------- 23 files changed, 98 insertions(+), 70 deletions(-) delete mode 100644 .changeset/brave-items-cover.md delete mode 100644 .changeset/famous-roses-hide.md delete mode 100644 .changeset/gold-walls-explode.md delete mode 100644 .changeset/good-pans-joke.md delete mode 100644 .changeset/khaki-parrots-invite.md delete mode 100644 .changeset/metal-turtles-design.md delete mode 100644 .changeset/olive-wolves-dress.md diff --git a/.changeset/brave-items-cover.md b/.changeset/brave-items-cover.md deleted file mode 100644 index ad1de7aa9f..0000000000 --- a/.changeset/brave-items-cover.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@ice/runtime': patch ---- - -feat: support props for KeepAliveOutlet diff --git a/.changeset/famous-roses-hide.md b/.changeset/famous-roses-hide.md deleted file mode 100644 index 424e5c83a0..0000000000 --- a/.changeset/famous-roses-hide.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'rax-compat': patch ---- - -fix createElement runtime import diff --git a/.changeset/gold-walls-explode.md b/.changeset/gold-walls-explode.md deleted file mode 100644 index 4b1bfc22ee..0000000000 --- a/.changeset/gold-walls-explode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@ice/runtime': patch ---- - -feat: support API dynamic to allow import component in different scenario diff --git a/.changeset/good-pans-joke.md b/.changeset/good-pans-joke.md deleted file mode 100644 index 906286b068..0000000000 --- a/.changeset/good-pans-joke.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@ice/rspack-config': patch -'@ice/bundles': patch -'@ice/app': patch ---- - -feat: upgrade icepack for new features diff --git a/.changeset/khaki-parrots-invite.md b/.changeset/khaki-parrots-invite.md deleted file mode 100644 index 5e8f6ae192..0000000000 --- a/.changeset/khaki-parrots-invite.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@ice/rspack-config': patch -'@ice/shared-config': patch -'@ice/bundles': patch -'@ice/runtime': patch -'@ice/app': patch ---- - -refactor: the compilation for data-loader diff --git a/.changeset/metal-turtles-design.md b/.changeset/metal-turtles-design.md deleted file mode 100644 index 2b2f421240..0000000000 --- a/.changeset/metal-turtles-design.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@ice/runtime': patch ---- - -fix: compat with the route path did not match when single route mode diff --git a/.changeset/olive-wolves-dress.md b/.changeset/olive-wolves-dress.md deleted file mode 100644 index 760db56f11..0000000000 --- a/.changeset/olive-wolves-dress.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@ice/app': patch ---- - -feat: support add plugin by cli option diff --git a/packages/bundles/CHANGELOG.md b/packages/bundles/CHANGELOG.md index 3eaf98b64f..7ccfedc70c 100644 --- a/packages/bundles/CHANGELOG.md +++ b/packages/bundles/CHANGELOG.md @@ -1,5 +1,12 @@ # Changelog +## 0.2.6 + +### Patch Changes + +- 8275f13f: feat: upgrade icepack for new features +- 0d3cfd59: refactor: the compilation for data-loader + ## 0.2.5 ### Patch Changes diff --git a/packages/bundles/package.json b/packages/bundles/package.json index eb16f54e2f..c497190ddd 100644 --- a/packages/bundles/package.json +++ b/packages/bundles/package.json @@ -1,6 +1,6 @@ { "name": "@ice/bundles", - "version": "0.2.5", + "version": "0.2.6", "license": "MIT", "author": "ICE", "description": "Basic dependencies for ice.", diff --git a/packages/ice/CHANGELOG.md b/packages/ice/CHANGELOG.md index 3f0685cd30..5a277e39dd 100644 --- a/packages/ice/CHANGELOG.md +++ b/packages/ice/CHANGELOG.md @@ -1,5 +1,23 @@ # Changelog +## 3.4.6 + +### Patch Changes + +- 8275f13f: feat: upgrade icepack for new features +- 0d3cfd59: refactor: the compilation for data-loader +- ac36776f: feat: support add plugin by cli option +- Updated dependencies [ba811d72] +- Updated dependencies [a7c76b62] +- Updated dependencies [8275f13f] +- Updated dependencies [0d3cfd59] +- Updated dependencies [d0a748f6] + - @ice/runtime@1.4.3 + - @ice/rspack-config@1.1.6 + - @ice/bundles@0.2.6 + - @ice/shared-config@1.2.6 + - @ice/webpack-config@1.1.13 + ## 3.4.5 ### Patch Changes diff --git a/packages/ice/package.json b/packages/ice/package.json index 09e218a8e8..02ccf1b4f6 100644 --- a/packages/ice/package.json +++ b/packages/ice/package.json @@ -1,6 +1,6 @@ { "name": "@ice/app", - "version": "3.4.5", + "version": "3.4.6", "description": "provide scripts and configuration used by web framework ice", "type": "module", "main": "./esm/index.js", @@ -47,12 +47,12 @@ "bugs": "https://github.com/alibaba/ice/issues", "homepage": "https://v3.ice.work", "dependencies": { - "@ice/bundles": "0.2.5", + "@ice/bundles": "0.2.6", "@ice/route-manifest": "1.2.2", - "@ice/runtime": "^1.4.2", - "@ice/shared-config": "1.2.5", - "@ice/webpack-config": "1.1.12", - "@ice/rspack-config": "1.1.5", + "@ice/runtime": "^1.4.3", + "@ice/shared-config": "1.2.6", + "@ice/webpack-config": "1.1.13", + "@ice/rspack-config": "1.1.6", "@swc/helpers": "0.5.1", "@types/express": "^4.17.14", "address": "^1.1.2", diff --git a/packages/plugin-i18n/package.json b/packages/plugin-i18n/package.json index 722e1f7c76..526379fe96 100644 --- a/packages/plugin-i18n/package.json +++ b/packages/plugin-i18n/package.json @@ -56,8 +56,8 @@ "webpack-dev-server": "4.15.0" }, "peerDependencies": { - "@ice/app": "^3.4.5", - "@ice/runtime": "^1.4.2" + "@ice/app": "^3.4.6", + "@ice/runtime": "^1.4.3" }, "publishConfig": { "access": "public" diff --git a/packages/rax-compat/CHANGELOG.md b/packages/rax-compat/CHANGELOG.md index 504a33c554..1bd588dbc1 100644 --- a/packages/rax-compat/CHANGELOG.md +++ b/packages/rax-compat/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## 0.2.11 + +### Patch Changes + +- 886c4de8: fix createElement runtime import + ## 0.2.10 ### Patch Changes diff --git a/packages/rax-compat/package.json b/packages/rax-compat/package.json index 640189c8c3..8578ededa8 100644 --- a/packages/rax-compat/package.json +++ b/packages/rax-compat/package.json @@ -1,6 +1,6 @@ { "name": "rax-compat", - "version": "0.2.10", + "version": "0.2.11", "description": "Rax compatible mode, running rax project on the react runtime.", "files": [ "esm", diff --git a/packages/rspack-config/CHANGELOG.md b/packages/rspack-config/CHANGELOG.md index 174c2e90b1..2a1b0a8dfe 100644 --- a/packages/rspack-config/CHANGELOG.md +++ b/packages/rspack-config/CHANGELOG.md @@ -1,5 +1,16 @@ # @ice/rspack-config +## 1.1.6 + +### Patch Changes + +- 8275f13f: feat: upgrade icepack for new features +- 0d3cfd59: refactor: the compilation for data-loader +- Updated dependencies [8275f13f] +- Updated dependencies [0d3cfd59] + - @ice/bundles@0.2.6 + - @ice/shared-config@1.2.6 + ## 1.1.5 ### Patch Changes diff --git a/packages/rspack-config/package.json b/packages/rspack-config/package.json index 7dc61377cb..ade042ed32 100644 --- a/packages/rspack-config/package.json +++ b/packages/rspack-config/package.json @@ -1,6 +1,6 @@ { "name": "@ice/rspack-config", - "version": "1.1.5", + "version": "1.1.6", "repository": "alibaba/ice", "bugs": "https://github.com/alibaba/ice/issues", "homepage": "https://v3.ice.work", @@ -15,8 +15,8 @@ "*.d.ts" ], "dependencies": { - "@ice/bundles": "0.2.5", - "@ice/shared-config": "1.2.5" + "@ice/bundles": "0.2.6", + "@ice/shared-config": "1.2.6" }, "devDependencies": { "@rspack/core": "0.5.7" diff --git a/packages/runtime/CHANGELOG.md b/packages/runtime/CHANGELOG.md index 0128be12da..c3b1ce2b3e 100644 --- a/packages/runtime/CHANGELOG.md +++ b/packages/runtime/CHANGELOG.md @@ -1,5 +1,14 @@ # @ice/runtime +## 1.4.3 + +### Patch Changes + +- ba811d72: feat: support props for KeepAliveOutlet +- a7c76b62: feat: support API dynamic to allow import component in different scenario +- 0d3cfd59: refactor: the compilation for data-loader +- d0a748f6: fix: compat with the route path did not match when single route mode + ## 1.4.2 ### Patch Changes diff --git a/packages/runtime/package.json b/packages/runtime/package.json index f949a30dcd..8795ebf39b 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@ice/runtime", - "version": "1.4.2", + "version": "1.4.3", "description": "Runtime module for ice.js", "type": "module", "types": "./esm/index.d.ts", diff --git a/packages/shared-config/CHANGELOG.md b/packages/shared-config/CHANGELOG.md index d134ee6c69..49dcc30e88 100644 --- a/packages/shared-config/CHANGELOG.md +++ b/packages/shared-config/CHANGELOG.md @@ -1,5 +1,14 @@ # @ice/shared-config +## 1.2.6 + +### Patch Changes + +- 0d3cfd59: refactor: the compilation for data-loader +- Updated dependencies [8275f13f] +- Updated dependencies [0d3cfd59] + - @ice/bundles@0.2.6 + ## 1.2.5 ### Patch Changes diff --git a/packages/shared-config/package.json b/packages/shared-config/package.json index c4174969aa..ee34fb0b2e 100644 --- a/packages/shared-config/package.json +++ b/packages/shared-config/package.json @@ -1,6 +1,6 @@ { "name": "@ice/shared-config", - "version": "1.2.5", + "version": "1.2.6", "repository": "alibaba/ice", "bugs": "https://github.com/alibaba/ice/issues", "homepage": "https://v3.ice.work", @@ -17,7 +17,7 @@ "*.d.ts" ], "dependencies": { - "@ice/bundles": "0.2.5", + "@ice/bundles": "0.2.6", "@rollup/pluginutils": "^4.2.0", "browserslist": "^4.22.1", "consola": "^2.15.3", diff --git a/packages/webpack-config/CHANGELOG.md b/packages/webpack-config/CHANGELOG.md index 2e555083c6..58e36ee7fd 100644 --- a/packages/webpack-config/CHANGELOG.md +++ b/packages/webpack-config/CHANGELOG.md @@ -1,5 +1,14 @@ # Changelog +## 1.1.13 + +### Patch Changes + +- Updated dependencies [8275f13f] +- Updated dependencies [0d3cfd59] + - @ice/bundles@0.2.6 + - @ice/shared-config@1.2.6 + ## 1.1.12 ### Patch Changes diff --git a/packages/webpack-config/package.json b/packages/webpack-config/package.json index 47c171fb76..8edae22d73 100644 --- a/packages/webpack-config/package.json +++ b/packages/webpack-config/package.json @@ -1,6 +1,6 @@ { "name": "@ice/webpack-config", - "version": "1.1.12", + "version": "1.1.13", "repository": "alibaba/ice", "bugs": "https://github.com/alibaba/ice/issues", "homepage": "https://v3.ice.work", @@ -15,8 +15,8 @@ "*.d.ts" ], "dependencies": { - "@ice/shared-config": "1.2.5", - "@ice/bundles": "0.2.5", + "@ice/shared-config": "1.2.6", + "@ice/bundles": "0.2.6", "fast-glob": "^3.2.11", "process": "^0.11.10" }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9ceb044d92..2b6da01fde 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1647,22 +1647,22 @@ importers: packages/ice: dependencies: '@ice/bundles': - specifier: 0.2.5 + specifier: 0.2.6 version: link:../bundles '@ice/route-manifest': specifier: 1.2.2 version: link:../route-manifest '@ice/rspack-config': - specifier: 1.1.5 + specifier: 1.1.6 version: link:../rspack-config '@ice/runtime': - specifier: ^1.4.2 + specifier: ^1.4.3 version: link:../runtime '@ice/shared-config': - specifier: 1.2.5 + specifier: 1.2.6 version: link:../shared-config '@ice/webpack-config': - specifier: 1.1.12 + specifier: 1.1.13 version: link:../webpack-config '@swc/helpers': specifier: 0.5.1 @@ -2332,10 +2332,10 @@ importers: packages/rspack-config: dependencies: '@ice/bundles': - specifier: 0.2.5 + specifier: 0.2.6 version: link:../bundles '@ice/shared-config': - specifier: 1.2.5 + specifier: 1.2.6 version: link:../shared-config devDependencies: '@rspack/core': @@ -2406,7 +2406,7 @@ importers: packages/shared-config: dependencies: '@ice/bundles': - specifier: 0.2.5 + specifier: 0.2.6 version: link:../bundles '@rollup/pluginutils': specifier: ^4.2.0 @@ -2449,10 +2449,10 @@ importers: packages/webpack-config: dependencies: '@ice/bundles': - specifier: 0.2.5 + specifier: 0.2.6 version: link:../bundles '@ice/shared-config': - specifier: 1.2.5 + specifier: 1.2.6 version: link:../shared-config fast-glob: specifier: ^3.2.11