From ed9df911a8bc49b0369b4bbd1e58210154f9ddea Mon Sep 17 00:00:00 2001 From: ClarkXia Date: Tue, 1 Nov 2022 16:54:09 +0800 Subject: [PATCH 01/22] refactor: type dependencies (#638) * refactor: types dependencies * chore: types * fix: tsconfig * chore: optimize code * fix: conflict --- packages/ice/package.json | 6 +- packages/ice/src/commands/build.ts | 7 +- packages/ice/src/commands/start.ts | 6 +- packages/ice/src/commands/test.ts | 2 +- packages/ice/src/config.ts | 3 +- packages/ice/src/createService.ts | 8 +- packages/ice/src/getWatchEvents.ts | 4 +- packages/ice/src/index.ts | 2 +- .../src/middlewares/ssr/renderMiddleware.ts | 4 +- packages/ice/src/plugins/web/index.ts | 2 +- packages/ice/src/routes.ts | 2 +- packages/ice/src/service/analyze.ts | 2 +- packages/ice/src/service/config.ts | 2 +- packages/ice/src/service/preBundleCJSDeps.ts | 2 +- packages/ice/src/service/runtimeGenerator.ts | 2 +- packages/ice/src/service/serverCompiler.ts | 5 +- packages/ice/src/service/watchSource.ts | 2 +- packages/ice/src/service/webpackCompiler.ts | 18 +-- packages/ice/src/tasks/web/index.ts | 2 +- packages/ice/src/test/defineJestConfig.ts | 2 +- .../{types/src => ice/src/types}/generator.ts | 0 packages/ice/src/types/index.ts | 5 + .../{types/src => ice/src/types}/plugin.ts | 11 +- .../src => ice/src/types}/userConfig.ts | 2 +- packages/ice/src/utils/ServerCompileTask.ts | 2 +- packages/ice/src/utils/getRouterBasename.ts | 2 +- packages/ice/src/utils/getRuntimeModules.ts | 2 +- .../ice/src/utils/getServerCompilerPlugin.ts | 4 +- packages/ice/src/utils/mergeTaskConfig.ts | 2 +- packages/ice/src/utils/prepareURLs.ts | 2 +- packages/ice/src/utils/runtimeEnv.ts | 2 +- packages/ice/src/webpack/DataLoaderPlugin.ts | 2 +- .../ice/src/webpack/ServerCompilerPlugin.ts | 2 +- packages/miniapp-runtime/package.json | 1 - packages/miniapp-runtime/src/app/connect.tsx | 2 +- .../miniapp-runtime/src/app/runClientApp.tsx | 5 +- packages/miniapp-runtime/src/dsl/common.ts | 2 +- .../miniapp-runtime/src/interface/hydrate.ts | 2 +- .../index.ts => miniapp-runtime/src/types.ts} | 2 +- packages/plugin-antd/package.json | 2 +- packages/plugin-antd/src/index.ts | 2 +- packages/plugin-auth/package.json | 3 +- packages/plugin-auth/src/index.ts | 2 +- packages/plugin-auth/src/runtime/index.tsx | 2 +- packages/plugin-auth/src/types.ts | 3 +- packages/plugin-css-assets-local/package.json | 2 +- packages/plugin-css-assets-local/src/index.ts | 2 +- packages/plugin-fusion/package.json | 2 +- packages/plugin-fusion/src/index.ts | 2 +- packages/plugin-jsx-plus/package.json | 2 +- packages/plugin-jsx-plus/src/index.ts | 2 +- packages/plugin-jsx-plus/src/types.ts | 0 packages/plugin-miniapp/package.json | 2 +- packages/plugin-miniapp/src/index.ts | 2 +- packages/plugin-miniapp/src/miniapp/index.ts | 2 +- .../src/miniapp/webpack/plugins/MiniPlugin.ts | 3 +- .../webpack/plugins/NormalModulesPlugin.ts | 1 - packages/plugin-miniapp/src/types.ts | 5 +- packages/plugin-moment-locales/package.json | 2 +- packages/plugin-moment-locales/src/index.ts | 2 +- packages/plugin-pha/package.json | 2 +- packages/plugin-pha/src/generateManifest.ts | 2 +- packages/plugin-pha/src/index.ts | 3 +- packages/plugin-rax-compat/package.json | 4 +- packages/plugin-rax-compat/src/index.ts | 2 +- packages/plugin-request/package.json | 3 +- packages/plugin-request/src/index.ts | 2 +- packages/plugin-request/src/runtime.ts | 2 +- packages/plugin-store/package.json | 3 +- packages/plugin-store/src/index.ts | 2 +- packages/plugin-store/src/runtime.tsx | 2 +- packages/runtime/package.json | 3 +- packages/runtime/src/App.tsx | 2 +- packages/runtime/src/AppContext.tsx | 2 +- packages/runtime/src/AppData.tsx | 2 +- packages/runtime/src/AppRouter.tsx | 2 +- packages/runtime/src/ClientOnly.tsx | 7 +- packages/runtime/src/Document.tsx | 2 +- packages/runtime/src/RouteContext.ts | 2 +- packages/runtime/src/RouteWrapper.tsx | 2 +- packages/runtime/src/appConfig.ts | 2 +- packages/runtime/src/dataLoader.ts | 2 +- packages/runtime/src/index.ts | 4 +- packages/runtime/src/matchRoutes.ts | 2 +- packages/runtime/src/requestContext.ts | 2 +- packages/runtime/src/routes.tsx | 2 +- packages/runtime/src/routesConfig.ts | 2 +- packages/runtime/src/runClientApp.tsx | 2 +- packages/runtime/src/runServerApp.tsx | 2 +- packages/runtime/src/runtime.tsx | 2 +- .../src/runtime.ts => runtime/src/types.ts} | 0 .../runtime/src/utils/getCurrentRoutePath.ts | 2 +- packages/runtime/tests/routes.test.tsx | 2 +- packages/style-import/package.json | 3 - packages/types/CHANGELOG.md | 5 - packages/types/README.md | 25 ---- packages/types/package.json | 50 -------- packages/types/src/index.ts | 7 - packages/types/tsconfig.json | 9 -- packages/webpack-config/package.json | 7 +- packages/webpack-config/src/config/assets.ts | 6 +- packages/webpack-config/src/config/css.ts | 7 +- .../webpack-config/src/getCompilerPlugins.ts | 2 +- packages/webpack-config/src/index.ts | 17 ++- .../config.ts => webpack-config/src/types.ts} | 26 ++-- .../src/unPlugins/compilation.ts | 2 +- .../src/unPlugins/redirectImport.ts | 10 +- pnpm-lock.yaml | 120 +++++------------- tsconfig.json | 18 --- website/docs/guide/plugins/plugin-dev.md | 12 +- 110 files changed, 215 insertions(+), 368 deletions(-) rename packages/{types/src => ice/src/types}/generator.ts (100%) create mode 100644 packages/ice/src/types/index.ts rename packages/{types/src => ice/src/types}/plugin.ts (91%) rename packages/{types/src => ice/src/types}/userConfig.ts (98%) rename packages/{types/src/miniapp/index.ts => miniapp-runtime/src/types.ts} (99%) delete mode 100644 packages/plugin-jsx-plus/src/types.ts rename packages/{types/src/runtime.ts => runtime/src/types.ts} (100%) delete mode 100644 packages/types/CHANGELOG.md delete mode 100644 packages/types/README.md delete mode 100644 packages/types/package.json delete mode 100644 packages/types/src/index.ts delete mode 100644 packages/types/tsconfig.json rename packages/{types/src/config.ts => webpack-config/src/types.ts} (82%) delete mode 100644 tsconfig.json diff --git a/packages/ice/package.json b/packages/ice/package.json index af5652512..8f2d7ccbd 100644 --- a/packages/ice/package.json +++ b/packages/ice/package.json @@ -4,7 +4,10 @@ "description": "provide scripts and configuration used by web framework ice", "type": "module", "main": "./esm/index.js", - "exports": "./esm/index.js", + "exports": { + ".": "./esm/index.js", + "./types": "./esm/types/index.js" + }, "bin": { "ice": "./bin/ice-cli.mjs" }, @@ -63,7 +66,6 @@ "temp": "^0.9.4" }, "devDependencies": { - "@ice/types": "^1.0.0", "@types/babel__generator": "^7.6.4", "@types/babel__traverse": "^7.17.1", "@types/cross-spawn": "^6.0.2", diff --git a/packages/ice/src/commands/build.ts b/packages/ice/src/commands/build.ts index 68a3bb8e4..5955e95af 100644 --- a/packages/ice/src/commands/build.ts +++ b/packages/ice/src/commands/build.ts @@ -1,11 +1,11 @@ import consola from 'consola'; import { getWebpackConfig } from '@ice/webpack-config'; import type { Context, TaskConfig } from 'build-scripts'; +import webpack from 'webpack'; import type { StatsError, Stats } from 'webpack'; -import type { Config } from '@ice/types'; -import type { ServerCompiler, GetAppConfig, GetRoutesConfig, ExtendsPluginAPI } from '@ice/types/esm/plugin.js'; -import webpack from '@ice/bundles/compiled/webpack/index.js'; +import type { Config } from '@ice/webpack-config/esm/types'; import type ora from '@ice/bundles/compiled/ora/index.js'; +import type { ServerCompiler, GetAppConfig, GetRoutesConfig, ExtendsPluginAPI } from '../types/plugin.js'; import webpackCompiler from '../service/webpackCompiler.js'; import formatWebpackMessages from '../utils/formatWebpackMessages.js'; import { RUNTIME_TMP_DIR } from '../constant.js'; @@ -26,7 +26,6 @@ const build = async ( const webpackConfigs = taskConfigs.map(({ config }) => getWebpackConfig({ config, rootDir, - // @ts-expect-error fix type error of compiled webpack webpack, runtimeTmpDir: RUNTIME_TMP_DIR, })); diff --git a/packages/ice/src/commands/start.ts b/packages/ice/src/commands/start.ts index 9537837ae..6ca70908f 100644 --- a/packages/ice/src/commands/start.ts +++ b/packages/ice/src/commands/start.ts @@ -5,12 +5,12 @@ import type { Configuration as DevServerConfiguration } from 'webpack-dev-server import type { Context, TaskConfig } from 'build-scripts'; import type { StatsError, Compiler, Configuration } from 'webpack'; import lodash from '@ice/bundles/compiled/lodash/index.js'; -import type { Config } from '@ice/types'; -import type { ExtendsPluginAPI, ServerCompiler, GetAppConfig, GetRoutesConfig } from '@ice/types/esm/plugin.js'; +import type { Config } from '@ice/webpack-config/esm/types'; import type { AppConfig, RenderMode } from '@ice/runtime'; import { getWebpackConfig } from '@ice/webpack-config'; import webpack from '@ice/bundles/compiled/webpack/index.js'; import type ora from '@ice/bundles/compiled/ora/index.js'; +import type { ExtendsPluginAPI, ServerCompiler, GetAppConfig, GetRoutesConfig } from '../types/plugin.js'; import webpackCompiler from '../service/webpackCompiler.js'; import formatWebpackMessages from '../utils/formatWebpackMessages.js'; import prepareURLs from '../utils/prepareURLs.js'; @@ -87,7 +87,7 @@ const start = async ( interface StartDevServerOptions { context: Context; - webpackConfigs: Configuration | Configuration[]; + webpackConfigs: Configuration[]; taskConfigs: TaskConfig[]; spinner: ora.Ora; hooksAPI: { diff --git a/packages/ice/src/commands/test.ts b/packages/ice/src/commands/test.ts index f8d634d44..c73b9861a 100644 --- a/packages/ice/src/commands/test.ts +++ b/packages/ice/src/commands/test.ts @@ -1,5 +1,5 @@ import type { Context, TaskConfig } from 'build-scripts'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; import type ora from '@ice/bundles/compiled/ora/index.js'; function test( diff --git a/packages/ice/src/config.ts b/packages/ice/src/config.ts index 6d521e635..194c8a469 100644 --- a/packages/ice/src/config.ts +++ b/packages/ice/src/config.ts @@ -2,9 +2,10 @@ import { createRequire } from 'module'; import trustCert from '@ice/bundles/compiled/trusted-cert/index.js'; import fse from 'fs-extra'; import consola from 'consola'; -import type { UserConfig, Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; import type { UserConfigContext } from 'build-scripts'; import lodash from '@ice/bundles/compiled/lodash/index.js'; +import type { UserConfig } from './types/userConfig.js'; const require = createRequire(import.meta.url); const { merge } = lodash; diff --git a/packages/ice/src/createService.ts b/packages/ice/src/createService.ts index cb0ac8a47..9cf2f33bb 100644 --- a/packages/ice/src/createService.ts +++ b/packages/ice/src/createService.ts @@ -4,10 +4,11 @@ import { createRequire } from 'module'; import { Context } from 'build-scripts'; import consola from 'consola'; import type { CommandArgs, CommandName } from 'build-scripts'; -import type { AppConfig, Config, PluginData } from '@ice/types'; -import type { DeclarationData } from '@ice/types/esm/generator.js'; -import type { ExtendsPluginAPI } from '@ice/types/esm/plugin.js'; +import type { Config } from '@ice/webpack-config/esm/types'; +import type { AppConfig } from '@ice/runtime/esm/types'; import webpack from '@ice/bundles/compiled/webpack/index.js'; +import type { DeclarationData } from './types/generator.js'; +import type { PluginData, ExtendsPluginAPI } from './types/plugin.js'; import Generator from './service/runtimeGenerator.js'; import { createServerCompiler } from './service/serverCompiler.js'; import createWatch from './service/watchSource.js'; @@ -96,7 +97,6 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt removeEvent: removeWatchEvent, }, context: { - // @ts-expect-error repack type can not match with original type webpack, }, serverCompileTask, diff --git a/packages/ice/src/getWatchEvents.ts b/packages/ice/src/getWatchEvents.ts index 11d7bfcf1..ff5291de9 100644 --- a/packages/ice/src/getWatchEvents.ts +++ b/packages/ice/src/getWatchEvents.ts @@ -1,8 +1,8 @@ import * as path from 'path'; import consola from 'consola'; -import type { ServerCompiler, WatchEvent } from '@ice/types/esm/plugin.js'; import type { Context } from 'build-scripts'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; +import type { ServerCompiler, WatchEvent } from './types/plugin.js'; import { generateRoutesInfo } from './routes.js'; import type Generator from './service/runtimeGenerator'; import getGlobalStyleGlobPattern from './utils/getGlobalStyleGlobPattern.js'; diff --git a/packages/ice/src/index.ts b/packages/ice/src/index.ts index 6a50d91db..0a6ccbd57 100644 --- a/packages/ice/src/index.ts +++ b/packages/ice/src/index.ts @@ -1,4 +1,4 @@ -import type { UserConfig } from '@ice/types'; +import type { UserConfig } from './types/userConfig.js'; export function defineConfig(config: UserConfig) { return config; diff --git a/packages/ice/src/middlewares/ssr/renderMiddleware.ts b/packages/ice/src/middlewares/ssr/renderMiddleware.ts index b66e280e7..76d0c2379 100644 --- a/packages/ice/src/middlewares/ssr/renderMiddleware.ts +++ b/packages/ice/src/middlewares/ssr/renderMiddleware.ts @@ -5,9 +5,9 @@ import type { ServerContext, RenderMode } from '@ice/runtime'; import consola from 'consola'; // @ts-expect-error FIXME: esm type error import matchRoutes from '@ice/runtime/matchRoutes'; -import type { ExtendsPluginAPI } from '@ice/types/esm/plugin.js'; import type { TaskConfig } from 'build-scripts'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; +import type { ExtendsPluginAPI } from '../../types/plugin.js'; import getRouterBasename from '../../utils/getRouterBasename.js'; import dynamicImport from '../../utils/dynamicImport.js'; diff --git a/packages/ice/src/plugins/web/index.ts b/packages/ice/src/plugins/web/index.ts index b2c8a1e6f..c99971361 100644 --- a/packages/ice/src/plugins/web/index.ts +++ b/packages/ice/src/plugins/web/index.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import consola from 'consola'; import chalk from 'chalk'; -import type { Plugin } from '@ice/types'; +import type { Plugin } from '../../types/plugin.js'; import ReCompilePlugin from '../../webpack/ReCompilePlugin.js'; import DataLoaderPlugin from '../../webpack/DataLoaderPlugin.js'; import { getRouteExportConfig } from '../../service/config.js'; diff --git a/packages/ice/src/routes.ts b/packages/ice/src/routes.ts index 190100973..bd4ec038d 100644 --- a/packages/ice/src/routes.ts +++ b/packages/ice/src/routes.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import { formatNestedRouteManifest, generateRouteManifest } from '@ice/route-manifest'; import type { NestedRouteManifest } from '@ice/route-manifest'; -import type { UserConfig } from '@ice/types'; +import type { UserConfig } from './types/userConfig.js'; import { getFileExports } from './service/analyze.js'; import formatPath from './utils/formatPath.js'; diff --git a/packages/ice/src/service/analyze.ts b/packages/ice/src/service/analyze.ts index b6c806602..24eeda5ec 100644 --- a/packages/ice/src/service/analyze.ts +++ b/packages/ice/src/service/analyze.ts @@ -7,7 +7,7 @@ import { transform, build } from 'esbuild'; import type { Loader, Plugin } from 'esbuild'; import consola from 'consola'; import type { TaskConfig } from 'build-scripts'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; import { getCache, setCache } from '../utils/persistentCache.js'; import { getFileHash } from '../utils/hash.js'; import scanPlugin from '../esbuild/scan.js'; diff --git a/packages/ice/src/service/config.ts b/packages/ice/src/service/config.ts index d4995b837..bcee7dc08 100644 --- a/packages/ice/src/service/config.ts +++ b/packages/ice/src/service/config.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import fs from 'fs-extra'; -import type { ServerCompiler } from '@ice/types/esm/plugin.js'; import consola from 'consola'; +import type { ServerCompiler } from '../types/plugin.js'; import removeTopLevelCode from '../esbuild/removeTopLevelCode.js'; import { getCache, setCache } from '../utils/persistentCache.js'; import { getFileHash } from '../utils/hash.js'; diff --git a/packages/ice/src/service/preBundleCJSDeps.ts b/packages/ice/src/service/preBundleCJSDeps.ts index d30216dfa..074f1bfd6 100644 --- a/packages/ice/src/service/preBundleCJSDeps.ts +++ b/packages/ice/src/service/preBundleCJSDeps.ts @@ -6,7 +6,7 @@ import { build } from 'esbuild'; import type { Plugin } from 'esbuild'; import { resolve as resolveExports } from 'resolve.exports'; import moduleLexer from '@ice/bundles/compiled/es-module-lexer/index.js'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; import type { TaskConfig } from 'build-scripts'; import flattenId from '../utils/flattenId.js'; import formatPath from '../utils/formatPath.js'; diff --git a/packages/ice/src/service/runtimeGenerator.ts b/packages/ice/src/service/runtimeGenerator.ts index 2eedc0e72..5eae2fe3b 100644 --- a/packages/ice/src/service/runtimeGenerator.ts +++ b/packages/ice/src/service/runtimeGenerator.ts @@ -21,7 +21,7 @@ import type { DeclarationData, Registration, TemplateOptions, -} from '@ice/types/esm/generator.js'; +} from '../types/generator.js'; import getGlobalStyleGlobPattern from '../utils/getGlobalStyleGlobPattern.js'; const { debounce } = lodash; diff --git a/packages/ice/src/service/serverCompiler.ts b/packages/ice/src/service/serverCompiler.ts index 48a62cdc9..5fc83e747 100644 --- a/packages/ice/src/service/serverCompiler.ts +++ b/packages/ice/src/service/serverCompiler.ts @@ -2,11 +2,12 @@ import * as path from 'path'; import { createHash } from 'crypto'; import consola from 'consola'; import esbuild from 'esbuild'; -import type { Config, UserConfig } from '@ice/types'; -import type { ServerCompiler } from '@ice/types/esm/plugin.js'; +import type { Config } from '@ice/webpack-config/esm/types'; import lodash from '@ice/bundles/compiled/lodash/index.js'; import type { TaskConfig } from 'build-scripts'; import { getCompilerPlugins } from '@ice/webpack-config'; +import type { ServerCompiler } from '../types/plugin.js'; +import type { UserConfig } from '../types/userConfig.js'; import escapeLocalIdent from '../utils/escapeLocalIdent.js'; import cssModulesPlugin from '../esbuild/cssModules.js'; import aliasPlugin from '../esbuild/alias.js'; diff --git a/packages/ice/src/service/watchSource.ts b/packages/ice/src/service/watchSource.ts index dc5547316..f3e1df73c 100644 --- a/packages/ice/src/service/watchSource.ts +++ b/packages/ice/src/service/watchSource.ts @@ -1,7 +1,7 @@ import * as chokidar from 'chokidar'; import micromatch from 'micromatch'; import type { WatchOptions } from 'chokidar'; -import type { WatchEvent } from '@ice/types/esm/plugin.js'; +import type { WatchEvent } from '../types/plugin.js'; import formatPath from '../utils/formatPath.js'; function createWatch(options: { diff --git a/packages/ice/src/service/webpackCompiler.ts b/packages/ice/src/service/webpackCompiler.ts index e1da54c8d..154cc7f97 100644 --- a/packages/ice/src/service/webpackCompiler.ts +++ b/packages/ice/src/service/webpackCompiler.ts @@ -1,15 +1,15 @@ -import webpack from '@ice/bundles/compiled/webpack/index.js'; +import webpackBundler from '@ice/bundles/compiled/webpack/index.js'; import type ora from '@ice/bundles/compiled/ora/index.js'; import consola from 'consola'; import type { TaskConfig, Context } from 'build-scripts'; -import type { Compiler, Configuration } from 'webpack'; -import type { Urls, ServerCompiler, GetAppConfig, GetRoutesConfig, ExtendsPluginAPI } from '@ice/types/esm/plugin.js'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; +import type webpack from 'webpack'; +import type { Urls, ServerCompiler, GetAppConfig, GetRoutesConfig, ExtendsPluginAPI } from '../types/plugin.js'; import formatWebpackMessages from '../utils/formatWebpackMessages.js'; async function webpackCompiler(options: { context: Context; - webpackConfigs: Configuration | Configuration[]; + webpackConfigs: webpack.Configuration[]; taskConfigs: TaskConfig[]; urls?: Urls; spinner: ora.Ora; @@ -39,7 +39,7 @@ async function webpackCompiler(options: { }); // Add default plugins for spinner - webpackConfigs[0].plugins.push((compiler: Compiler) => { + webpackConfigs[0].plugins.push((compiler: webpack.Compiler) => { compiler.hooks.beforeCompile.tap('spinner', () => { spinner.text = 'compiling...\n'; }); @@ -47,10 +47,10 @@ async function webpackCompiler(options: { spinner.stop(); }); }); - let compiler: Compiler; + let compiler: webpack.Compiler; try { - // @ts-expect-error ignore error with different webpack referer - compiler = webpack(webpackConfigs as Configuration); + // @ts-ignore + compiler = webpackBundler(webpackConfigs); } catch (err) { consola.error('Webpack compile error.'); consola.error(err.message || err); diff --git a/packages/ice/src/tasks/web/index.ts b/packages/ice/src/tasks/web/index.ts index 7b99dec1b..e134eb1ee 100644 --- a/packages/ice/src/tasks/web/index.ts +++ b/packages/ice/src/tasks/web/index.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import { createRequire } from 'module'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; import { CACHE_DIR, RUNTIME_TMP_DIR } from '../../constant.js'; import { getRoutePathsFromCache } from '../../utils/getRoutePaths.js'; diff --git a/packages/ice/src/test/defineJestConfig.ts b/packages/ice/src/test/defineJestConfig.ts index a443dab06..de7efcb7e 100644 --- a/packages/ice/src/test/defineJestConfig.ts +++ b/packages/ice/src/test/defineJestConfig.ts @@ -1,7 +1,7 @@ import * as path from 'path'; import type { Config as JestConfig } from 'jest'; import fse from 'fs-extra'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; import lodash from '@ice/bundles/compiled/lodash/index.js'; import getTaskConfig from './getTaskConfig.js'; diff --git a/packages/types/src/generator.ts b/packages/ice/src/types/generator.ts similarity index 100% rename from packages/types/src/generator.ts rename to packages/ice/src/types/generator.ts diff --git a/packages/ice/src/types/index.ts b/packages/ice/src/types/index.ts new file mode 100644 index 000000000..c329bdc2f --- /dev/null +++ b/packages/ice/src/types/index.ts @@ -0,0 +1,5 @@ +export * from './generator.js'; +export * from './plugin.js'; +export * from './userConfig.js'; +// Export type webpack for same instance of webpack. +export type { Config, webpack } from '@ice/webpack-config/esm/types'; \ No newline at end of file diff --git a/packages/types/src/plugin.ts b/packages/ice/src/types/plugin.ts similarity index 91% rename from packages/types/src/plugin.ts rename to packages/ice/src/types/plugin.ts index 29a9a0779..2b92e0b1f 100644 --- a/packages/types/src/plugin.ts +++ b/packages/ice/src/types/plugin.ts @@ -1,12 +1,11 @@ -import type webpack from 'webpack'; +import type webpack from '@ice/bundles/compiled/webpack'; import type { _Plugin, CommandArgs, TaskConfig } from 'build-scripts'; -import type { Configuration, Stats } from 'webpack'; -import type WebpackDevServer from 'webpack-dev-server'; +import type { Configuration, Stats, WebpackOptionsNormalized } from '@ice/bundles/compiled/webpack'; import type { BuildOptions, BuildResult } from 'esbuild'; import type { NestedRouteManifest } from '@ice/route-manifest'; -import type { Config } from './config.js'; +import type { Config } from '@ice/webpack-config/esm/types'; +import type { AssetsManifest } from '@ice/runtime/esm/types'; import type { DeclarationData, AddRenderFile, AddTemplateFiles, ModifyRenderData, AddDataLoaderImport, Render } from './generator.js'; -import type { AssetsManifest } from './runtime.js'; type AddExport = (exportData: DeclarationData) => void; type RemoveExport = (removeSource: string | string[]) => void; @@ -89,7 +88,7 @@ export interface HookLifecycle { 'after.build.compile': AfterCommandCompileOptions & { serverEntryRef: { current: string } }; 'after.start.devServer': { urls: Urls; - devServer: WebpackDevServer; + devServer: WebpackOptionsNormalized['devServer']; }; } diff --git a/packages/types/src/userConfig.ts b/packages/ice/src/types/userConfig.ts similarity index 98% rename from packages/types/src/userConfig.ts rename to packages/ice/src/types/userConfig.ts index 9b3e92ff0..db500e638 100644 --- a/packages/types/src/userConfig.ts +++ b/packages/ice/src/types/userConfig.ts @@ -1,7 +1,7 @@ import type { DefineRouteFunction } from '@ice/route-manifest'; import type { PluginList } from 'build-scripts'; import type { UnpluginOptions } from 'unplugin'; -import type { Config, ModifyWebpackConfig, MinimizerOptions } from './config'; +import type { Config, ModifyWebpackConfig, MinimizerOptions } from '@ice/webpack-config/esm/types'; import type { OverwritePluginAPI } from './plugin'; interface SyntaxFeatures { diff --git a/packages/ice/src/utils/ServerCompileTask.ts b/packages/ice/src/utils/ServerCompileTask.ts index 43a5040aa..490bbe43d 100644 --- a/packages/ice/src/utils/ServerCompileTask.ts +++ b/packages/ice/src/utils/ServerCompileTask.ts @@ -1,4 +1,4 @@ -import type { ServerCompiler } from '@ice/types/esm/plugin.js'; +import type { ServerCompiler } from '../types/plugin.js'; /** * Get server compile promise task in middlewares or plugins. diff --git a/packages/ice/src/utils/getRouterBasename.ts b/packages/ice/src/utils/getRouterBasename.ts index 716e8bb5e..6d3024d56 100644 --- a/packages/ice/src/utils/getRouterBasename.ts +++ b/packages/ice/src/utils/getRouterBasename.ts @@ -1,5 +1,5 @@ import type { AppConfig } from '@ice/runtime'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; import type { TaskConfig } from 'build-scripts'; const getRouterBasename = (taskConfig: TaskConfig, appConfig: AppConfig) => { diff --git a/packages/ice/src/utils/getRuntimeModules.ts b/packages/ice/src/utils/getRuntimeModules.ts index 030fb1dfd..79fe0eff7 100644 --- a/packages/ice/src/utils/getRuntimeModules.ts +++ b/packages/ice/src/utils/getRuntimeModules.ts @@ -1,4 +1,4 @@ -import type { PluginData } from '@ice/types'; +import type { PluginData } from '../types/plugin.js'; export interface RuntimeModule { staticRuntime: boolean; diff --git a/packages/ice/src/utils/getServerCompilerPlugin.ts b/packages/ice/src/utils/getServerCompilerPlugin.ts index 25bb48080..afc1fc5c4 100644 --- a/packages/ice/src/utils/getServerCompilerPlugin.ts +++ b/packages/ice/src/utils/getServerCompilerPlugin.ts @@ -1,6 +1,6 @@ import path from 'path'; -import type { ServerCompiler, ExtendsPluginAPI } from '@ice/types/esm/plugin.js'; -import type { UserConfig } from '@ice/types'; +import type { ServerCompiler, ExtendsPluginAPI } from '../types/plugin.js'; +import type { UserConfig } from '../types/userConfig.js'; import ServerCompilerPlugin from '../webpack/ServerCompilerPlugin.js'; import { SERVER_OUTPUT_DIR } from '../constant.js'; import getServerEntry from './getServerEntry.js'; diff --git a/packages/ice/src/utils/mergeTaskConfig.ts b/packages/ice/src/utils/mergeTaskConfig.ts index ebf1f446c..e7ce124ec 100644 --- a/packages/ice/src/utils/mergeTaskConfig.ts +++ b/packages/ice/src/utils/mergeTaskConfig.ts @@ -1,5 +1,5 @@ import type { TaskConfig } from 'build-scripts'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/webpack-config/esm/types'; import lodash from '@ice/bundles/compiled/lodash/index.js'; const { mergeWith } = lodash; diff --git a/packages/ice/src/utils/prepareURLs.ts b/packages/ice/src/utils/prepareURLs.ts index 6f53341f4..2fb30b4f4 100644 --- a/packages/ice/src/utils/prepareURLs.ts +++ b/packages/ice/src/utils/prepareURLs.ts @@ -10,7 +10,7 @@ import url from 'url'; import address from 'address'; -import type { Urls } from '@ice/types/esm/plugin.js'; +import type { Urls } from '../types/plugin.js'; export default function prepareUrls( protocol: string, diff --git a/packages/ice/src/utils/runtimeEnv.ts b/packages/ice/src/utils/runtimeEnv.ts index 6abb53a6d..c3b409729 100644 --- a/packages/ice/src/utils/runtimeEnv.ts +++ b/packages/ice/src/utils/runtimeEnv.ts @@ -3,7 +3,7 @@ import * as fs from 'fs'; import * as dotenv from 'dotenv'; import { expand as dotenvExpand } from 'dotenv-expand'; import type { CommandArgs } from 'build-scripts'; -import type { AppConfig } from '@ice/types'; +import type { AppConfig } from '@ice/runtime/esm/types'; export interface Envs { [key: string]: string; diff --git a/packages/ice/src/webpack/DataLoaderPlugin.ts b/packages/ice/src/webpack/DataLoaderPlugin.ts index 11fe0adba..2ade8ea3d 100644 --- a/packages/ice/src/webpack/DataLoaderPlugin.ts +++ b/packages/ice/src/webpack/DataLoaderPlugin.ts @@ -1,9 +1,9 @@ import * as path from 'path'; import fse from 'fs-extra'; import consola from 'consola'; -import type { ServerCompiler } from '@ice/types/esm/plugin.js'; import type { Compiler } from 'webpack'; import webpack from '@ice/bundles/compiled/webpack/index.js'; +import type { ServerCompiler } from '../types/plugin.js'; import { RUNTIME_TMP_DIR } from '../constant.js'; import { getRoutePathsFromCache } from '../utils/getRoutePaths.js'; diff --git a/packages/ice/src/webpack/ServerCompilerPlugin.ts b/packages/ice/src/webpack/ServerCompilerPlugin.ts index 78cde4be8..0ce7a04c8 100644 --- a/packages/ice/src/webpack/ServerCompilerPlugin.ts +++ b/packages/ice/src/webpack/ServerCompilerPlugin.ts @@ -1,5 +1,5 @@ -import type { ExtendsPluginAPI, ServerCompiler } from '@ice/types/esm/plugin.js'; import type { Compiler, Compilation } from 'webpack'; +import type { ExtendsPluginAPI, ServerCompiler } from '../types/plugin.js'; const pluginName = 'ServerCompilerPlugin'; diff --git a/packages/miniapp-runtime/package.json b/packages/miniapp-runtime/package.json index 0d322fba3..1d7b589ff 100644 --- a/packages/miniapp-runtime/package.json +++ b/packages/miniapp-runtime/package.json @@ -25,7 +25,6 @@ "sideEffects": false, "dependencies": { "@ice/shared": "^1.0.0", - "@ice/types": "^1.0.0", "@ice/runtime": "^1.0.0", "miniapp-history": "^0.1.7" }, diff --git a/packages/miniapp-runtime/src/app/connect.tsx b/packages/miniapp-runtime/src/app/connect.tsx index 9bc0689f9..34b950df4 100644 --- a/packages/miniapp-runtime/src/app/connect.tsx +++ b/packages/miniapp-runtime/src/app/connect.tsx @@ -1,8 +1,8 @@ import { EMPTY_OBJ, hooks } from '@ice/shared'; -import type { MiniappAppConfig } from '@ice/types'; import React, { createElement } from 'react'; import * as ReactDOM from 'react-dom'; import { ConfigProvider, DataProvider } from '@ice/runtime'; +import type { MiniappAppConfig } from '../types.js'; import { Current, getPageInstance, incrementId, injectPageInstance, } from '../index.js'; diff --git a/packages/miniapp-runtime/src/app/runClientApp.tsx b/packages/miniapp-runtime/src/app/runClientApp.tsx index f15a019e8..6e9ff069e 100644 --- a/packages/miniapp-runtime/src/app/runClientApp.tsx +++ b/packages/miniapp-runtime/src/app/runClientApp.tsx @@ -1,9 +1,8 @@ import React from 'react'; import type { - AppContext, RouteWrapperConfig, -} from '@ice/types'; + AppContext, RouteWrapperConfig, RunClientAppOptions, +} from '@ice/runtime'; import { AppContextProvider, AppDataProvider, getAppData, getAppConfig, Runtime } from '@ice/runtime'; -import type { RunClientAppOptions } from '@ice/runtime'; import App from './App.js'; import { createMiniApp } from './connect.js'; import { setHistory } from './history.js'; diff --git a/packages/miniapp-runtime/src/dsl/common.ts b/packages/miniapp-runtime/src/dsl/common.ts index 2e402aeff..5273d45f9 100644 --- a/packages/miniapp-runtime/src/dsl/common.ts +++ b/packages/miniapp-runtime/src/dsl/common.ts @@ -1,7 +1,7 @@ /* eslint-disable dot-notation */ import { EMPTY_OBJ, ensure, hooks, isArray, isFunction, isString, isUndefined, Shortcuts } from '@ice/shared'; -import type { MiniappPageConfig } from '@ice/types'; import type * as React from 'react'; +import type { MiniappPageConfig } from '../types.js'; import { raf } from '../bom/raf.js'; import { BEHAVIORS, CUSTOM_WRAPPER, EXTERNAL_CLASSES, ON_HIDE, ON_LOAD, ON_READY, ON_SHOW, OPTIONS, PAGE_INIT, VIEW } from '../constants/index.js'; diff --git a/packages/miniapp-runtime/src/interface/hydrate.ts b/packages/miniapp-runtime/src/interface/hydrate.ts index f6c2296bf..24ff2f273 100644 --- a/packages/miniapp-runtime/src/interface/hydrate.ts +++ b/packages/miniapp-runtime/src/interface/hydrate.ts @@ -1,5 +1,5 @@ import type { Shortcuts } from '@ice/shared'; -import type { MiniappPageConfig } from '@ice/types'; +import type { MiniappPageConfig } from '../types.js'; export interface MpInstance { config: MiniappPageConfig; diff --git a/packages/types/src/miniapp/index.ts b/packages/miniapp-runtime/src/types.ts similarity index 99% rename from packages/types/src/miniapp/index.ts rename to packages/miniapp-runtime/src/types.ts index 334cda383..e1d0d8542 100644 --- a/packages/types/src/miniapp/index.ts +++ b/packages/miniapp-runtime/src/types.ts @@ -1,7 +1,7 @@ /** * 微信小程序全局 Window 配置和页面配置的公共项目 */ -interface CommonConfig { + interface CommonConfig { /** 导航栏背景颜色,HexColor * @default: "#000000" */ diff --git a/packages/plugin-antd/package.json b/packages/plugin-antd/package.json index 0c3638952..9006332e2 100644 --- a/packages/plugin-antd/package.json +++ b/packages/plugin-antd/package.json @@ -16,7 +16,7 @@ "url": "https://github.com/ice-lab/ice-next/tree/master/packages/plugin-antd" }, "devDependencies": { - "@ice/types": "^1.0.0" + "@ice/app": "^3.0.0" }, "dependencies": { "@ice/style-import": "^1.0.0" diff --git a/packages/plugin-antd/src/index.ts b/packages/plugin-antd/src/index.ts index 9b465dc0d..38f1a850f 100644 --- a/packages/plugin-antd/src/index.ts +++ b/packages/plugin-antd/src/index.ts @@ -1,5 +1,5 @@ import { createRequire } from 'module'; -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; import styleImportPlugin from '@ice/style-import'; interface PluginOptions { diff --git a/packages/plugin-auth/package.json b/packages/plugin-auth/package.json index 3662fd43b..369029c90 100644 --- a/packages/plugin-auth/package.json +++ b/packages/plugin-auth/package.json @@ -43,7 +43,8 @@ "!esm/**/*.map" ], "devDependencies": { - "@ice/types": "^1.0.0", + "@ice/app": "^3.0.0", + "@ice/runtime": "^1.0.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "regenerator-runtime": "^0.13.9" diff --git a/packages/plugin-auth/src/index.ts b/packages/plugin-auth/src/index.ts index b83f9200e..4489f5d48 100644 --- a/packages/plugin-auth/src/index.ts +++ b/packages/plugin-auth/src/index.ts @@ -1,4 +1,4 @@ -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; const PLUGIN_NAME = '@ice/plugin-auth'; diff --git a/packages/plugin-auth/src/runtime/index.tsx b/packages/plugin-auth/src/runtime/index.tsx index 59d0682b5..8d4e22813 100644 --- a/packages/plugin-auth/src/runtime/index.tsx +++ b/packages/plugin-auth/src/runtime/index.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import type { RuntimePlugin, AppProvider, RouteWrapper } from '@ice/types'; +import type { RuntimePlugin, AppProvider, RouteWrapper } from '@ice/runtime/esm/types'; import type { AuthConfig, AuthType, Auth } from '../types.js'; import { AuthProvider, useAuth } from './Auth.js'; import type { InjectProps } from './Auth.js'; diff --git a/packages/plugin-auth/src/types.ts b/packages/plugin-auth/src/types.ts index e8711d5bb..dd5d8727e 100644 --- a/packages/plugin-auth/src/types.ts +++ b/packages/plugin-auth/src/types.ts @@ -1,5 +1,6 @@ import type * as React from 'react'; -import type { RouteConfig } from '@ice/types'; +import type { RouteConfig } from '@ice/runtime/esm/types'; + export interface AuthConfig { initialAuth: { [auth: string]: boolean; diff --git a/packages/plugin-css-assets-local/package.json b/packages/plugin-css-assets-local/package.json index a268f5a0d..f2e1d1bdc 100644 --- a/packages/plugin-css-assets-local/package.json +++ b/packages/plugin-css-assets-local/package.json @@ -25,7 +25,7 @@ "consola": "^2.15.3" }, "devDependencies": { - "@ice/types": "^1.0.0" + "@ice/app": "^3.0.0" }, "scripts": { "watch": "tsc -w", diff --git a/packages/plugin-css-assets-local/src/index.ts b/packages/plugin-css-assets-local/src/index.ts index de01b10a8..4b810451d 100644 --- a/packages/plugin-css-assets-local/src/index.ts +++ b/packages/plugin-css-assets-local/src/index.ts @@ -1,4 +1,4 @@ -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; // @ts-expect-error cjs module error import ExtractCssAssetsWebpackPlugin from 'extract-css-assets-webpack-plugin'; import consola from 'consola'; diff --git a/packages/plugin-fusion/package.json b/packages/plugin-fusion/package.json index 9bc7a1e18..d675838f7 100644 --- a/packages/plugin-fusion/package.json +++ b/packages/plugin-fusion/package.json @@ -14,7 +14,7 @@ "@ice/style-import": "^1.0.0" }, "devDependencies": { - "@ice/types": "^1.0.0" + "@ice/app": "^3.0.0" }, "repository": { "type": "http", diff --git a/packages/plugin-fusion/src/index.ts b/packages/plugin-fusion/src/index.ts index 473403734..26537fb1f 100644 --- a/packages/plugin-fusion/src/index.ts +++ b/packages/plugin-fusion/src/index.ts @@ -1,5 +1,5 @@ import { createRequire } from 'module'; -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; import styleImportPlugin from '@ice/style-import'; interface PluginOptions { diff --git a/packages/plugin-jsx-plus/package.json b/packages/plugin-jsx-plus/package.json index 4ad691b4a..37946afad 100644 --- a/packages/plugin-jsx-plus/package.json +++ b/packages/plugin-jsx-plus/package.json @@ -28,7 +28,7 @@ "!esm/**/*.map" ], "devDependencies": { - "@ice/types": "^1.0.0", + "@ice/app": "^3.0.0", "@types/react": "^18.0.20", "@types/react-dom": "^18.0.6" }, diff --git a/packages/plugin-jsx-plus/src/index.ts b/packages/plugin-jsx-plus/src/index.ts index 77317a4c7..223342766 100644 --- a/packages/plugin-jsx-plus/src/index.ts +++ b/packages/plugin-jsx-plus/src/index.ts @@ -1,6 +1,6 @@ import path from 'path'; import { createRequire } from 'module'; -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; import { transformSync } from '@babel/core'; const require = createRequire(import.meta.url); diff --git a/packages/plugin-jsx-plus/src/types.ts b/packages/plugin-jsx-plus/src/types.ts deleted file mode 100644 index e69de29bb..000000000 diff --git a/packages/plugin-miniapp/package.json b/packages/plugin-miniapp/package.json index ddcfb46b5..18a39d620 100644 --- a/packages/plugin-miniapp/package.json +++ b/packages/plugin-miniapp/package.json @@ -30,7 +30,7 @@ "regenerator-runtime": "^0.11.0" }, "devDependencies": { - "@ice/types": "^1.0.0", + "@ice/app": "^3.0.0", "webpack": "^5.73.0" }, "repository": { diff --git a/packages/plugin-miniapp/src/index.ts b/packages/plugin-miniapp/src/index.ts index 8946548d2..5dc66062f 100644 --- a/packages/plugin-miniapp/src/index.ts +++ b/packages/plugin-miniapp/src/index.ts @@ -1,7 +1,7 @@ import path from 'path'; import consola from 'consola'; import chalk from 'chalk'; -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; import getMiniappTask from './miniapp/index.js'; import { ALL_PLATFORMS, WEB } from './constant.js'; diff --git a/packages/plugin-miniapp/src/miniapp/index.ts b/packages/plugin-miniapp/src/miniapp/index.ts index ce74fe234..436dcb398 100644 --- a/packages/plugin-miniapp/src/miniapp/index.ts +++ b/packages/plugin-miniapp/src/miniapp/index.ts @@ -6,7 +6,7 @@ import * as path from 'path'; import { createRequire } from 'node:module'; import fg from 'fast-glob'; -import type { Config } from '@ice/types'; +import type { Config } from '@ice/app/esm/types'; import getMiniappPlatformConfig from '../platforms/index.js'; import getMiniappWebpackConfig from './webpack/index.js'; diff --git a/packages/plugin-miniapp/src/miniapp/webpack/plugins/MiniPlugin.ts b/packages/plugin-miniapp/src/miniapp/webpack/plugins/MiniPlugin.ts index c4339c170..6fc72ce1f 100644 --- a/packages/plugin-miniapp/src/miniapp/webpack/plugins/MiniPlugin.ts +++ b/packages/plugin-miniapp/src/miniapp/webpack/plugins/MiniPlugin.ts @@ -3,7 +3,8 @@ import path from 'path'; import { createRequire } from 'module'; import type { RecursiveTemplate, UnRecursiveTemplate } from '@ice/shared'; -import type { Config, MiniappAppConfig, MiniappConfig } from '@ice/types'; +import type { Config } from '@ice/app/esm/types'; +import type { MiniappAppConfig, MiniappConfig } from '@ice/miniapp-runtime/esm/types'; import fs from 'fs-extra'; import { minify } from 'html-minifier'; import loaderUtils from '@ice/bundles/compiled/loader-utils/index.js'; diff --git a/packages/plugin-miniapp/src/miniapp/webpack/plugins/NormalModulesPlugin.ts b/packages/plugin-miniapp/src/miniapp/webpack/plugins/NormalModulesPlugin.ts index 9af832ff1..ef7115036 100644 --- a/packages/plugin-miniapp/src/miniapp/webpack/plugins/NormalModulesPlugin.ts +++ b/packages/plugin-miniapp/src/miniapp/webpack/plugins/NormalModulesPlugin.ts @@ -1,5 +1,4 @@ import type webpack from '@ice/bundles/compiled/webpack/index.js'; - import * as walk from 'acorn-walk'; import SingleEntryDependency from '../dependencies/SingleEntryDependency.js'; import { componentConfig } from '../template/component.js'; diff --git a/packages/plugin-miniapp/src/types.ts b/packages/plugin-miniapp/src/types.ts index 4ffe0b958..bdc64a9f4 100644 --- a/packages/plugin-miniapp/src/types.ts +++ b/packages/plugin-miniapp/src/types.ts @@ -1,6 +1,5 @@ import type { RecursiveTemplate, UnRecursiveTemplate } from '@ice/shared'; -import type { Configuration } from 'webpack'; -import type { Config } from '@ice/types'; +import type { Config, webpack } from '@ice/app/esm/types'; export interface MiniappConfig { rootDir: string; @@ -43,4 +42,4 @@ export interface MiniappWebpackOptions { }; } -export type MiniappWebpackConfig = Pick; +export type MiniappWebpackConfig = Pick; diff --git a/packages/plugin-moment-locales/package.json b/packages/plugin-moment-locales/package.json index 6e291c240..58be83f3a 100644 --- a/packages/plugin-moment-locales/package.json +++ b/packages/plugin-moment-locales/package.json @@ -16,7 +16,7 @@ "url": "https://github.com/ice-lab/ice-next/tree/master/packages/plugin-moment-locales" }, "devDependencies": { - "@ice/types": "^1.0.0" + "@ice/app": "^3.0.0" }, "publishConfig": { "access": "public" diff --git a/packages/plugin-moment-locales/src/index.ts b/packages/plugin-moment-locales/src/index.ts index 43e5273fe..4625a6de3 100644 --- a/packages/plugin-moment-locales/src/index.ts +++ b/packages/plugin-moment-locales/src/index.ts @@ -1,4 +1,4 @@ -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; interface PluginOptions { locales: string | string[]; diff --git a/packages/plugin-pha/package.json b/packages/plugin-pha/package.json index 380832d8b..1edd4ea41 100644 --- a/packages/plugin-pha/package.json +++ b/packages/plugin-pha/package.json @@ -22,7 +22,7 @@ "lodash.clonedeep": "^4.5.0" }, "devDependencies": { - "@ice/types": "^1.0.0", + "@ice/app": "^3.0.0", "esbuild": "^0.14.51", "webpack": "^5.73.0", "webpack-dev-server": "^4.9.2" diff --git a/packages/plugin-pha/src/generateManifest.ts b/packages/plugin-pha/src/generateManifest.ts index e643a9e74..300339cdd 100644 --- a/packages/plugin-pha/src/generateManifest.ts +++ b/packages/plugin-pha/src/generateManifest.ts @@ -1,6 +1,6 @@ import * as path from 'path'; import * as fs from 'fs'; -import type { GetAppConfig, GetRoutesConfig, ServerCompiler } from '@ice/types/esm/plugin.js'; +import type { GetAppConfig, GetRoutesConfig, ServerCompiler } from '@ice/app/esm/types'; import { parseManifest, rewriteAppWorker, getAppWorkerUrl, getMultipleManifest, type ParseOptions } from './manifestHelpers.js'; import type { Compiler } from './index.js'; diff --git a/packages/plugin-pha/src/index.ts b/packages/plugin-pha/src/index.ts index be3d3fb18..1aa758110 100644 --- a/packages/plugin-pha/src/index.ts +++ b/packages/plugin-pha/src/index.ts @@ -1,8 +1,7 @@ import * as path from 'path'; import consola from 'consola'; import chalk from 'chalk'; -import type { Plugin } from '@ice/types'; -import type { GetAppConfig, GetRoutesConfig } from '@ice/types/esm/plugin.js'; +import type { Plugin, GetAppConfig, GetRoutesConfig } from '@ice/app/esm/types'; import generateManifest from './generateManifest.js'; import createPHAMiddleware from './phaMiddleware.js'; diff --git a/packages/plugin-rax-compat/package.json b/packages/plugin-rax-compat/package.json index 669dadcf9..adcf61dfe 100644 --- a/packages/plugin-rax-compat/package.json +++ b/packages/plugin-rax-compat/package.json @@ -28,8 +28,8 @@ "stylesheet-loader": "^0.9.1" }, "devDependencies": { - "@ice/types": "^1.0.0", - "@types/webpack": "^5.28.0" + "@ice/app": "^3.0.0", + "webpack": "^5.73.0" }, "repository": { "type": "http", diff --git a/packages/plugin-rax-compat/src/index.ts b/packages/plugin-rax-compat/src/index.ts index 067690aee..9c55db8a3 100644 --- a/packages/plugin-rax-compat/src/index.ts +++ b/packages/plugin-rax-compat/src/index.ts @@ -1,7 +1,7 @@ import fs from 'fs'; import path from 'path'; import { createRequire } from 'module'; -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; import type { RuleSetRule } from 'webpack'; import consola from 'consola'; import merge from 'lodash.merge'; diff --git a/packages/plugin-request/package.json b/packages/plugin-request/package.json index 759810465..d1b8993f4 100644 --- a/packages/plugin-request/package.json +++ b/packages/plugin-request/package.json @@ -52,7 +52,8 @@ "axios": "^0.27.2" }, "devDependencies": { - "@ice/types": "^1.0.0", + "@ice/app": "^3.0.0", + "@ice/runtime": "^1.0.0", "@types/react": "^18.0.0", "@types/react-dom": "^18.0.0", "regenerator-runtime": "^0.13.9" diff --git a/packages/plugin-request/src/index.ts b/packages/plugin-request/src/index.ts index 1398d5012..a5e9aa1b4 100644 --- a/packages/plugin-request/src/index.ts +++ b/packages/plugin-request/src/index.ts @@ -1,4 +1,4 @@ -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; import type { Request, Interceptors, InterceptorRequest, InterceptorResponse } from './types'; // @ts-ignore diff --git a/packages/plugin-request/src/runtime.ts b/packages/plugin-request/src/runtime.ts index 70926373c..1d56f2f77 100644 --- a/packages/plugin-request/src/runtime.ts +++ b/packages/plugin-request/src/runtime.ts @@ -1,4 +1,4 @@ -import type { RuntimePlugin } from '@ice/types'; +import type { RuntimePlugin } from '@ice/runtime/esm/types'; import { createAxiosInstance, setAxiosInstance } from './request.js'; import type { RequestConfig } from './types'; diff --git a/packages/plugin-store/package.json b/packages/plugin-store/package.json index 6934ba259..d11ed5e85 100644 --- a/packages/plugin-store/package.json +++ b/packages/plugin-store/package.json @@ -43,7 +43,8 @@ "micromatch": "^4.0.5" }, "devDependencies": { - "@ice/types": "^1.0.0", + "@ice/app": "^3.0.0", + "@ice/runtime": "^1.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "@types/react": "^18.0.0", diff --git a/packages/plugin-store/src/index.ts b/packages/plugin-store/src/index.ts index f32497ce4..d95d30288 100644 --- a/packages/plugin-store/src/index.ts +++ b/packages/plugin-store/src/index.ts @@ -1,5 +1,5 @@ import * as path from 'path'; -import type { Config, Plugin } from '@ice/types'; +import type { Config, Plugin } from '@ice/app/esm/types'; import micromatch from 'micromatch'; import fg from 'fast-glob'; import { PAGE_STORE_MODULE, PAGE_STORE_PROVIDER, PAGE_STORE_INITIAL_STATES } from './constants.js'; diff --git a/packages/plugin-store/src/runtime.tsx b/packages/plugin-store/src/runtime.tsx index 0181045b9..39655bb0d 100644 --- a/packages/plugin-store/src/runtime.tsx +++ b/packages/plugin-store/src/runtime.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import type { RuntimePlugin, AppProvider, RouteWrapper } from '@ice/types'; +import type { RuntimePlugin, AppProvider, RouteWrapper } from '@ice/runtime/esm/types'; import { PAGE_STORE_INITIAL_STATES, PAGE_STORE_PROVIDER } from './constants.js'; import type { StoreConfig } from './types.js'; diff --git a/packages/runtime/package.json b/packages/runtime/package.json index 019979f6e..813628eae 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -14,6 +14,7 @@ "./matchRoutes": "./esm/matchRoutes.js", "./router": "./esm/router.js", "./single-router": "./esm/single-router.js", + "./types": "./esm/types.js", "./package.json": "./package.json" }, "files": [ @@ -30,7 +31,6 @@ "build": "tsc" }, "devDependencies": { - "@ice/types": "^1.0.0", "react": "^18.0.0", "react-dom": "^18.0.0", "@types/react": "^18.0.8", @@ -40,7 +40,6 @@ "sideEffects": false, "dependencies": { "@ice/jsx-runtime": "^0.1.0", - "@ice/types": "^1.0.0", "history": "^5.3.0", "react-router-dom": "^6.2.2" }, diff --git a/packages/runtime/src/App.tsx b/packages/runtime/src/App.tsx index 6e645c9e9..e18936f4a 100644 --- a/packages/runtime/src/App.tsx +++ b/packages/runtime/src/App.tsx @@ -1,7 +1,7 @@ import React, { useMemo } from 'react'; import type { Action, Location } from 'history'; import type { Navigator } from 'react-router-dom'; -import type { RouteWrapperConfig, AppRouterProps } from '@ice/types'; +import type { RouteWrapperConfig, AppRouterProps } from './types.js'; import AppErrorBoundary from './AppErrorBoundary.js'; import { useAppContext } from './AppContext.js'; import { createRouteElements } from './routes.js'; diff --git a/packages/runtime/src/AppContext.tsx b/packages/runtime/src/AppContext.tsx index 461c8973e..aa09b2537 100644 --- a/packages/runtime/src/AppContext.tsx +++ b/packages/runtime/src/AppContext.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import type { AppContext } from '@ice/types'; +import type { AppContext } from './types.js'; const Context = React.createContext(undefined); diff --git a/packages/runtime/src/AppData.tsx b/packages/runtime/src/AppData.tsx index a11e69ec2..c6600b411 100644 --- a/packages/runtime/src/AppData.tsx +++ b/packages/runtime/src/AppData.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import type { AppExport, AppData, RequestContext } from '@ice/types'; +import type { AppExport, AppData, RequestContext } from './types.js'; const Context = React.createContext(undefined); diff --git a/packages/runtime/src/AppRouter.tsx b/packages/runtime/src/AppRouter.tsx index bc2dd9992..070009e45 100644 --- a/packages/runtime/src/AppRouter.tsx +++ b/packages/runtime/src/AppRouter.tsx @@ -1,7 +1,7 @@ import * as React from 'react'; import type { RouteObject } from 'react-router-dom'; import { Router, useRoutes } from 'react-router-dom'; -import type { AppRouterProps } from '@ice/types'; +import type { AppRouterProps } from './types.js'; import { Router as RouterSingle, useRoutes as useRoutesSingle } from './single-router.js'; const AppRouter: React.ComponentType = (props) => { diff --git a/packages/runtime/src/ClientOnly.tsx b/packages/runtime/src/ClientOnly.tsx index 295308d55..acb2908c7 100644 --- a/packages/runtime/src/ClientOnly.tsx +++ b/packages/runtime/src/ClientOnly.tsx @@ -1,10 +1,11 @@ import React, { isValidElement } from 'react'; -import type { ComponentWithChildren } from '@ice/types'; import useMounted from './useMounted.js'; -const ClientOnly: ComponentWithChildren<{ fallback: React.ReactNode }> = ({ children, fallback }) => { +const ClientOnly: React.FC<{ + fallback: React.ReactElement; + children: () => React.ReactNode; +}> = ({ children, fallback }) => { const mounted = useMounted(); - // Ref https://github.com/facebook/docusaurus/blob/v2.1.0/packages/docusaurus/src/client/exports/BrowserOnly.tsx if (mounted) { if ( diff --git a/packages/runtime/src/Document.tsx b/packages/runtime/src/Document.tsx index c1ec7246e..29690f616 100644 --- a/packages/runtime/src/Document.tsx +++ b/packages/runtime/src/Document.tsx @@ -1,6 +1,6 @@ import * as React from 'react'; import type { ReactNode } from 'react'; -import type { WindowContext, RouteMatch, AssetsManifest } from '@ice/types'; +import type { WindowContext, RouteMatch, AssetsManifest } from './types.js'; import { useAppContext } from './AppContext.js'; import { useAppData } from './AppData.js'; import { getMeta, getTitle, getLinks, getScripts } from './routesConfig.js'; diff --git a/packages/runtime/src/RouteContext.ts b/packages/runtime/src/RouteContext.ts index e8cdabfec..113b50600 100644 --- a/packages/runtime/src/RouteContext.ts +++ b/packages/runtime/src/RouteContext.ts @@ -1,5 +1,5 @@ import * as React from 'react'; -import type { RouteData, RouteConfig } from '@ice/types'; +import type { RouteData, RouteConfig } from './types.js'; const DataContext = React.createContext(undefined); DataContext.displayName = 'Data'; diff --git a/packages/runtime/src/RouteWrapper.tsx b/packages/runtime/src/RouteWrapper.tsx index 451cdb532..04137aba6 100644 --- a/packages/runtime/src/RouteWrapper.tsx +++ b/packages/runtime/src/RouteWrapper.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import type { RouteWrapperConfig } from '@ice/types'; +import type { RouteWrapperConfig } from './types.js'; import { useAppContext } from './AppContext.js'; import { DataProvider, ConfigProvider } from './RouteContext.js'; diff --git a/packages/runtime/src/appConfig.ts b/packages/runtime/src/appConfig.ts index cdd11c1cf..be66c3212 100644 --- a/packages/runtime/src/appConfig.ts +++ b/packages/runtime/src/appConfig.ts @@ -1,4 +1,4 @@ -import type { AppConfig, AppExport } from '@ice/types'; +import type { AppConfig, AppExport } from './types.js'; const defaultAppConfig: AppConfig = { app: { diff --git a/packages/runtime/src/dataLoader.ts b/packages/runtime/src/dataLoader.ts index c50110bd3..a3bdc6a88 100644 --- a/packages/runtime/src/dataLoader.ts +++ b/packages/runtime/src/dataLoader.ts @@ -1,4 +1,4 @@ -import type { GetData, GetDataConfig } from '@ice/types'; +import type { GetData, GetDataConfig } from './types.js'; import getRequestContext from './requestContext.js'; interface Loaders { diff --git a/packages/runtime/src/index.ts b/packages/runtime/src/index.ts index 45d3eb3df..572cdacc4 100644 --- a/packages/runtime/src/index.ts +++ b/packages/runtime/src/index.ts @@ -16,7 +16,8 @@ import type { RouteWrapper, RenderMode, GetAppData, -} from '@ice/types'; + RouteWrapperConfig, +} from './types.js'; import Runtime from './runtime.js'; import App from './App.js'; import runClientApp from './runClientApp.js'; @@ -83,6 +84,7 @@ export type { AppContext, AppConfig, RouteConfig, + RouteWrapperConfig, RouteItem, ServerContext, AppProvider, diff --git a/packages/runtime/src/matchRoutes.ts b/packages/runtime/src/matchRoutes.ts index e33ef9252..c9d6e4f63 100644 --- a/packages/runtime/src/matchRoutes.ts +++ b/packages/runtime/src/matchRoutes.ts @@ -4,7 +4,7 @@ import type { Location } from 'history'; import type { RouteObject } from 'react-router-dom'; import { matchRoutes as originMatchRoutes } from 'react-router-dom'; -import type { RouteItem, RouteMatch } from '@ice/types'; +import type { RouteItem, RouteMatch } from './types.js'; import { matchRoutes as matchRoutesSingle } from './single-router.js'; export default function matchRoutes( diff --git a/packages/runtime/src/requestContext.ts b/packages/runtime/src/requestContext.ts index f581ebab8..81ccf643d 100644 --- a/packages/runtime/src/requestContext.ts +++ b/packages/runtime/src/requestContext.ts @@ -1,4 +1,4 @@ -import type { ServerContext, RequestContext } from '@ice/types'; +import type { ServerContext, RequestContext } from './types.js'; interface Location { pathname: string; diff --git a/packages/runtime/src/routes.tsx b/packages/runtime/src/routes.tsx index b9e4c35ba..b56cd1f99 100644 --- a/packages/runtime/src/routes.tsx +++ b/packages/runtime/src/routes.tsx @@ -1,5 +1,5 @@ import React from 'react'; -import type { RouteItem, RouteModules, RouteWrapperConfig, RouteMatch, RequestContext, RoutesConfig, RoutesData, RenderMode } from '@ice/types'; +import type { RouteItem, RouteModules, RouteWrapperConfig, RouteMatch, RequestContext, RoutesConfig, RoutesData, RenderMode } from './types.js'; import RouteWrapper from './RouteWrapper.js'; import { useAppContext } from './AppContext.js'; diff --git a/packages/runtime/src/routesConfig.ts b/packages/runtime/src/routesConfig.ts index 15ad90b4b..a70c36a15 100644 --- a/packages/runtime/src/routesConfig.ts +++ b/packages/runtime/src/routesConfig.ts @@ -1,4 +1,4 @@ -import type { RouteMatch, RoutesConfig, RouteConfig } from '@ice/types'; +import type { RouteMatch, RoutesConfig, RouteConfig } from './types.js'; export function getMeta( matches: RouteMatch[], diff --git a/packages/runtime/src/runClientApp.tsx b/packages/runtime/src/runClientApp.tsx index 7b093a515..715053bb9 100644 --- a/packages/runtime/src/runClientApp.tsx +++ b/packages/runtime/src/runClientApp.tsx @@ -5,7 +5,7 @@ import type { HashHistory, BrowserHistory, Action, Location, InitialEntry, Memor import type { AppContext, WindowContext, AppExport, RouteItem, AppRouterProps, RoutesData, RoutesConfig, RouteWrapperConfig, RuntimeModules, RouteMatch, RouteModules, AppConfig, AssetsManifest, -} from '@ice/types'; +} from './types.js'; import { createHistory as createHistorySingle } from './single-router.js'; import { setHistory } from './history.js'; import Runtime from './runtime.js'; diff --git a/packages/runtime/src/runServerApp.tsx b/packages/runtime/src/runServerApp.tsx index c79cf2801..4c6db411b 100644 --- a/packages/runtime/src/runServerApp.tsx +++ b/packages/runtime/src/runServerApp.tsx @@ -11,7 +11,7 @@ import type { RenderMode, DocumentComponent, RuntimeModules, -} from '@ice/types'; +} from './types.js'; import Runtime from './runtime.js'; import App from './App.js'; import { AppContextProvider } from './AppContext.js'; diff --git a/packages/runtime/src/runtime.tsx b/packages/runtime/src/runtime.tsx index 83066cd9b..ea4508223 100644 --- a/packages/runtime/src/runtime.tsx +++ b/packages/runtime/src/runtime.tsx @@ -14,7 +14,7 @@ import type { SetRender, AppRouterProps, ComponentWithChildren, -} from '@ice/types'; +} from './types.js'; import { useData, useConfig } from './RouteContext.js'; import { useAppContext } from './AppContext.js'; diff --git a/packages/types/src/runtime.ts b/packages/runtime/src/types.ts similarity index 100% rename from packages/types/src/runtime.ts rename to packages/runtime/src/types.ts diff --git a/packages/runtime/src/utils/getCurrentRoutePath.ts b/packages/runtime/src/utils/getCurrentRoutePath.ts index 80bcdb413..61d949c18 100644 --- a/packages/runtime/src/utils/getCurrentRoutePath.ts +++ b/packages/runtime/src/utils/getCurrentRoutePath.ts @@ -1,4 +1,4 @@ -import type { RouteMatch } from '@ice/types'; +import type { RouteMatch } from '../types.js'; /** * Get the current route path exclude the basename. diff --git a/packages/runtime/tests/routes.test.tsx b/packages/runtime/tests/routes.test.tsx index 3a6fcc477..80e27d6b9 100644 --- a/packages/runtime/tests/routes.test.tsx +++ b/packages/runtime/tests/routes.test.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { renderToString } from 'react-dom/server'; import { expect, it, describe, beforeEach, afterEach, vi } from 'vitest'; -import type { RouteComponent as IRouteComponent } from '@ice/types/esm/runtime'; +import type { RouteComponent as IRouteComponent } from '../src/types'; import RouteWrapper from '../src/RouteWrapper'; import { AppContextProvider } from '../src/AppContext'; import { diff --git a/packages/style-import/package.json b/packages/style-import/package.json index 47e2be278..7673182fc 100644 --- a/packages/style-import/package.json +++ b/packages/style-import/package.json @@ -15,9 +15,6 @@ "type": "http", "url": "https://github.com/ice-lab/ice-next/tree/master/packages/transform-import" }, - "devDependencies": { - "@ice/types": "^1.0.0" - }, "dependencies": { "es-module-lexer": "^1.0.2", "magic-string": "^0.26.2" diff --git a/packages/types/CHANGELOG.md b/packages/types/CHANGELOG.md deleted file mode 100644 index 6e4b56fa8..000000000 --- a/packages/types/CHANGELOG.md +++ /dev/null @@ -1,5 +0,0 @@ -# Changelog - -## v1.0.0 - -- [feat] provide basic type for develop ice plugin \ No newline at end of file diff --git a/packages/types/README.md b/packages/types/README.md deleted file mode 100644 index 26047b2fc..000000000 --- a/packages/types/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# @ice/types - -`@ice/types` provides basic types of webpack framework `ice`. - -## Usage - -develop plugin for ice: - -```js -// src/index.ts -import type { Plugin } from '@ice/types'; - -const plugin: Plugin = () => {}; -export default plugin; -``` - -develop runtime plugin for ice: - -```js -// runtime/index -import type { RuntimePlugin } from '@ice/types'; - -const runtime: RuntimePlugin = () => {}; -export default runtime; -``` diff --git a/packages/types/package.json b/packages/types/package.json deleted file mode 100644 index 135d72196..000000000 --- a/packages/types/package.json +++ /dev/null @@ -1,50 +0,0 @@ -{ - "name": "@ice/types", - "version": "1.0.0", - "description": "", - "type": "module", - "main": "./esm/index.js", - "types": "./esm/index.d.ts", - "exports": { - ".": "./esm/index.js", - "./runtime": { - "import": "./esm/runtime.js", - "types": "./esm/runtime.d.ts" - }, - "./plugin": { - "import": "./esm/plugin.js", - "types": "./esm/plugin.d.ts" - }, - "./generator": { - "import": "./esm/generator.js", - "types": "./esm/generator.d.ts" - } - }, - "scripts": { - "watch": "tsc -w", - "build": "tsc" - }, - "author": "ICE", - "license": "MIT", - "repository": "ice-lab/ice-next", - "bugs": "https://github.com/ice-lab/ice-next/issues", - "homepage": "https://next.ice.work", - "devDependencies": { - "@ice/route-manifest": "^1.0.0", - "@swc/core": "1.3.3", - "build-scripts": "^2.0.0-26", - "esbuild": "^0.14.51", - "eslint": "^8.14.0", - "eslint-webpack-plugin": "3.1.1", - "fork-ts-checker-webpack-plugin": "7.2.6", - "history": "^5.3.0", - "react": "^18.0.0", - "react-dom": "^18.2.0", - "react-router-dom": "^6.2.2", - "terser": "^5.12.1", - "typescript": "^4.6.4", - "unplugin": "^0.9.5", - "webpack": "^5.73.0", - "webpack-dev-server": "^4.7.4" - } -} diff --git a/packages/types/src/index.ts b/packages/types/src/index.ts deleted file mode 100644 index 130c9f0ab..000000000 --- a/packages/types/src/index.ts +++ /dev/null @@ -1,7 +0,0 @@ -export type { Config } from './config.js'; -export type { Plugin, PluginData } from './plugin.js'; -export type { UserConfig } from './userConfig.js'; - -export * from './runtime.js'; - -export * from './miniapp/index.js'; diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json deleted file mode 100644 index 5647eb03b..000000000 --- a/packages/types/tsconfig.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "baseUrl": "./", - "rootDir": "src", - "outDir": "esm" - }, - "include": ["src"] -} \ No newline at end of file diff --git a/packages/webpack-config/package.json b/packages/webpack-config/package.json index 91d5f8e84..f96a66096 100644 --- a/packages/webpack-config/package.json +++ b/packages/webpack-config/package.json @@ -6,7 +6,10 @@ "homepage": "https://next.ice.work", "type": "module", "main": "./esm/index.js", - "exports": "./esm/index.js", + "exports": { + ".": "./esm/index.js", + "./types": "./esm/types.js" + }, "files": [ "esm", "!esm/**/*.map" @@ -23,8 +26,6 @@ "fast-glob": "^3.2.11" }, "devDependencies": { - "@ice/types": "^1.0.0", - "build-scripts": "^2.0.0-26", "esbuild": "^0.14.51", "webpack": "^5.73.0", "webpack-dev-server": "^4.7.4" diff --git a/packages/webpack-config/src/config/assets.ts b/packages/webpack-config/src/config/assets.ts index 833d5042f..84d0d14c4 100644 --- a/packages/webpack-config/src/config/assets.ts +++ b/packages/webpack-config/src/config/assets.ts @@ -1,4 +1,6 @@ -import type { ModifyWebpackConfig } from '@ice/types/esm/config'; +import type webpack from 'webpack'; +import type { Configuration } from 'webpack'; +import type { ModifyWebpackConfig } from '../types.js'; type AssetRuleConfig = [RegExp, Record?, boolean?]; @@ -21,7 +23,7 @@ function configAssetsRule(config: AssetRuleConfig) { }; } -const assets: ModifyWebpackConfig = (config) => { +const assets: ModifyWebpackConfig = (config) => { const assetsRule = ([ [/\.woff2?$/, { mimetype: 'application/font-woff' }], [/\.ttf$/, { mimetype: 'application/octet-stream' }], diff --git a/packages/webpack-config/src/config/css.ts b/packages/webpack-config/src/config/css.ts index f76e1ede8..32c859fa6 100644 --- a/packages/webpack-config/src/config/css.ts +++ b/packages/webpack-config/src/config/css.ts @@ -3,8 +3,9 @@ import { createHash } from 'crypto'; // FIXME when resolve mini-css-extract-plugin symbol in test import MiniCssExtractPlugin from '@ice/bundles/compiled/mini-css-extract-plugin/dist/index.js'; import { sass, less, postcss } from '@ice/bundles'; -import type { ModifyWebpackConfig } from '@ice/types/esm/config'; -import type { LoaderContext } from 'webpack'; +import type webpack from 'webpack'; +import type { LoaderContext, Configuration } from 'webpack'; +import type { ModifyWebpackConfig } from '../types.js'; type CSSRuleConfig = [string, string?, Record?]; interface Options { @@ -92,7 +93,7 @@ function configCSSRule(config: CSSRuleConfig, options: Options) { }; } -const css: ModifyWebpackConfig = (config, ctx) => { +const css: ModifyWebpackConfig = (config, ctx) => { const { supportedBrowsers, publicPath, hashKey, cssFilename, cssChunkFilename } = ctx; const cssOutputFolder = 'css'; config.module.rules.push(...([ diff --git a/packages/webpack-config/src/getCompilerPlugins.ts b/packages/webpack-config/src/getCompilerPlugins.ts index ab146ad34..dc8c4fd95 100644 --- a/packages/webpack-config/src/getCompilerPlugins.ts +++ b/packages/webpack-config/src/getCompilerPlugins.ts @@ -1,8 +1,8 @@ -import type { Config } from '@ice/types'; import type { BuildOptions } from 'esbuild'; import unplugin from '@ice/bundles/compiled/unplugin/index.js'; import type { UnpluginOptions } from '@ice/bundles/compiled/unplugin/index.js'; import type { Configuration } from 'webpack'; +import type { Config } from './types.js'; import compilationPlugin from './unPlugins/compilation.js'; import compileExcludes from './compileExcludes.js'; diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index 30b0b0ff2..5370e4d23 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -11,10 +11,10 @@ import TerserPlugin from '@ice/bundles/compiled/terser-webpack-plugin/index.js'; import ForkTsCheckerPlugin from '@ice/bundles/compiled/fork-ts-checker-webpack-plugin/index.js'; import ESlintPlugin from '@ice/bundles/compiled/eslint-webpack-plugin/index.js'; import CopyPlugin from '@ice/bundles/compiled/copy-webpack-plugin/index.js'; -import type { Configuration, WebpackPluginInstance, NormalModule, Compiler } from 'webpack'; +import type { NormalModule, Compiler, Configuration } from 'webpack'; import type webpack from 'webpack'; -import type { Config } from '@ice/types'; import browserslist from 'browserslist'; +import type { Config, ModifyWebpackConfig } from './types.js'; import configAssets from './config/assets.js'; import configCss from './config/css.js'; import AssetsManifestPlugin from './webpackPlugins/AssetsManifestPlugin.js'; @@ -166,7 +166,7 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT compileExcludes, swcOptions, }); - const webpackConfig: Configuration = { + const webpackConfig = { mode, experiments: { layers: true, @@ -302,7 +302,7 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT }, }], }), - ].filter(Boolean) as unknown as WebpackPluginInstance[], + ].filter(Boolean), devServer: merge({ allowedHosts: 'all', headers: { @@ -328,8 +328,8 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT }, setupMiddlewares: middlewares, https, - }, devServer || {}), - }; + }, devServer || {}) as Config['devServer'], + } as Configuration; // tnpm / cnpm 安装时,webpack 5 的持久缓存无法生成,长时间将导致 OOM // 原因:[managedPaths](https://webpack.js.org/configuration/other-options/#managedpaths) 在 tnpm / cnpm 安装的情况下失效,导致持久缓存在处理 node_modules // 通过指定 [immutablePaths](https://webpack.js.org/configuration/other-options/#immutablepaths) 进行兼容 @@ -401,9 +401,8 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT hashKey, webpack, }; - const finalWebpackConfig = [configCss, configAssets, ...(configureWebpack || [])].reduce((result, next) => { - return next(result, ctx); - }, webpackConfig); + const finalWebpackConfig = [configCss, configAssets, ...(configureWebpack || [])] + .reduce((result, next: ModifyWebpackConfig) => next(result, ctx), webpackConfig); consola.debug('[webpack]', finalWebpackConfig); return finalWebpackConfig; }; diff --git a/packages/types/src/config.ts b/packages/webpack-config/src/types.ts similarity index 82% rename from packages/types/src/config.ts rename to packages/webpack-config/src/types.ts index 3aab5b450..7d3be8445 100644 --- a/packages/types/src/config.ts +++ b/packages/webpack-config/src/types.ts @@ -1,21 +1,20 @@ -import type webpack from 'webpack'; -import type { RuleSetRule, Configuration, Compiler, WebpackPluginInstance } from 'webpack'; +import type webpack from '@ice/bundles/compiled/webpack'; +import type { RuleSetRule, Configuration, Compiler, WebpackPluginInstance } from '@ice/bundles/compiled/webpack'; import type { ProxyConfigArray, ProxyConfigArrayItem, ProxyConfigMap, Middleware, ServerOptions, - Configuration as DevServerConfiguration, } from 'webpack-dev-server'; -import type { Options } from 'eslint-webpack-plugin'; -import type { ForkTsCheckerWebpackPluginOptions } from 'fork-ts-checker-webpack-plugin/lib/plugin-options'; -import type { UnpluginOptions, UnpluginContext } from 'unplugin'; +import type { Options } from '@ice/bundles/compiled/eslint-webpack-plugin'; +import type { ForkTsCheckerWebpackPluginOptions } from '@ice/bundles/compiled/fork-ts-checker-webpack-plugin'; +import type { UnpluginOptions, UnpluginContext } from '@ice/bundles/compiled/unplugin'; import type Server from 'webpack-dev-server'; -import type { ECMA } from 'terser'; import type { Config as SWCCompilationConfig } from '@swc/core'; import type { BuildOptions } from 'esbuild'; -import type { UserConfig } from './userConfig'; + +export type ECMA = 5 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020; // get type definitions from terser-webpack-plugin interface CustomOptions { @@ -28,10 +27,10 @@ interface PredefinedOptions { } export type MinimizerOptions = PredefinedOptions & InferDefaultType; -interface ConfigurationCtx extends Config { +interface ConfigurationCtx extends Config { supportedBrowsers: string[]; hashKey: string; - webpack: typeof webpack; + webpack: T; } type Experimental = Configuration['experiments']; @@ -62,7 +61,8 @@ interface TransformPlugin { loadInclude?: UnpluginOptions['loadInclude']; } -export type ModifyWebpackConfig = (config: Configuration, ctx: ConfigurationCtx) => Configuration; +export type ModifyWebpackConfig = (config: T, ctx: ConfigurationCtx) => T; +export type { webpack }; export interface Config { mode: 'none' | 'development' | 'production'; @@ -93,7 +93,7 @@ export interface Config { | WebpackPluginInstance )[]; - alias?: UserConfig['alias']; + alias?: Record; hash?: boolean | string; @@ -141,7 +141,7 @@ export interface Config { concatenateModules?: boolean; - devServer?: DevServerConfiguration; + devServer?: Server.Configuration; fastRefresh?: boolean; diff --git a/packages/webpack-config/src/unPlugins/compilation.ts b/packages/webpack-config/src/unPlugins/compilation.ts index 4459b144d..6d6df6e67 100644 --- a/packages/webpack-config/src/unPlugins/compilation.ts +++ b/packages/webpack-config/src/unPlugins/compilation.ts @@ -3,7 +3,7 @@ import swc from '@swc/core'; import type { Options as SwcConfig, ReactConfig } from '@swc/core'; import type { UnpluginOptions } from '@ice/bundles/compiled/unplugin/index.js'; import lodash from '@ice/bundles/compiled/lodash/index.js'; -import type { Config } from '@ice/types'; +import type { Config } from '../types.js'; const { merge } = lodash; const require = createRequire(import.meta.url); diff --git a/packages/webpack-config/src/unPlugins/redirectImport.ts b/packages/webpack-config/src/unPlugins/redirectImport.ts index dd61570a3..078ab6a37 100644 --- a/packages/webpack-config/src/unPlugins/redirectImport.ts +++ b/packages/webpack-config/src/unPlugins/redirectImport.ts @@ -4,8 +4,14 @@ import type { UnpluginOptions } from '@ice/bundles/compiled/unplugin/index.js'; import consola from 'consola'; import MagicString from '@ice/bundles/compiled/magic-string/index.js'; import { createFilter } from '@rollup/pluginutils'; -import type { DeclarationData } from '@ice/types/esm/generator.js'; -import type { Config } from '@ice/types'; +import type { Config } from '../types.js'; + +interface DeclarationData { + specifier: string | string[]; + source: string; + type?: boolean; + alias?: Record; +} interface Options { exportData: DeclarationData[]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 50a87d67e..36175fd9f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -696,7 +696,6 @@ importers: '@ice/bundles': ^0.1.0 '@ice/route-manifest': ^1.0.0 '@ice/runtime': ^1.0.0 - '@ice/types': ^1.0.0 '@ice/webpack-config': ^1.0.0 '@types/babel__generator': ^7.6.4 '@types/babel__traverse': ^7.17.1 @@ -771,7 +770,6 @@ importers: semver: 7.3.7 temp: 0.9.4 devDependencies: - '@ice/types': link:../types '@types/babel__generator': 7.6.4 '@types/babel__traverse': 7.18.2 '@types/cross-spawn': 6.0.2 @@ -835,7 +833,6 @@ importers: specifiers: '@ice/runtime': ^1.0.0 '@ice/shared': ^1.0.0 - '@ice/types': ^1.0.0 '@types/react': ^18.0.0 history: ^5.3.0 miniapp-history: ^0.1.7 @@ -844,7 +841,6 @@ importers: dependencies: '@ice/runtime': link:../runtime '@ice/shared': link:../shared - '@ice/types': link:../types miniapp-history: 0.1.7 devDependencies: '@types/react': 18.0.21 @@ -854,49 +850,51 @@ importers: packages/plugin-antd: specifiers: + '@ice/app': ^3.0.0 '@ice/style-import': ^1.0.0 - '@ice/types': ^1.0.0 dependencies: '@ice/style-import': link:../style-import devDependencies: - '@ice/types': link:../types + '@ice/app': link:../ice packages/plugin-auth: specifiers: - '@ice/types': ^1.0.0 + '@ice/app': ^3.0.0 + '@ice/runtime': ^1.0.0 '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 regenerator-runtime: ^0.13.9 devDependencies: - '@ice/types': link:../types + '@ice/app': link:../ice + '@ice/runtime': link:../runtime '@types/react': 18.0.21 '@types/react-dom': 18.0.6 regenerator-runtime: 0.13.9 packages/plugin-css-assets-local: specifiers: - '@ice/types': ^1.0.0 + '@ice/app': ^3.0.0 consola: ^2.15.3 extract-css-assets-webpack-plugin: ^0.2.10 dependencies: consola: 2.15.3 extract-css-assets-webpack-plugin: 0.2.10 devDependencies: - '@ice/types': link:../types + '@ice/app': link:../ice packages/plugin-fusion: specifiers: + '@ice/app': ^3.0.0 '@ice/style-import': ^1.0.0 - '@ice/types': ^1.0.0 dependencies: '@ice/style-import': link:../style-import devDependencies: - '@ice/types': link:../types + '@ice/app': link:../ice packages/plugin-jsx-plus: specifiers: '@babel/core': ^7.19.1 - '@ice/types': ^1.0.0 + '@ice/app': ^3.0.0 '@types/react': ^18.0.20 '@types/react-dom': ^18.0.6 babel-plugin-transform-jsx-class: ^0.1.3 @@ -916,18 +914,18 @@ importers: babel-plugin-transform-jsx-slot: 0.1.2 babel-runtime-jsx-plus: 0.1.5 devDependencies: - '@ice/types': link:../types + '@ice/app': link:../ice '@types/react': 18.0.21 '@types/react-dom': 18.0.6 packages/plugin-miniapp: specifiers: + '@ice/app': ^3.0.0 '@ice/bundles': ^0.1.0 '@ice/miniapp-loader': ^1.0.0 '@ice/miniapp-react-dom': ^1.0.0 '@ice/miniapp-runtime': ^1.0.0 '@ice/shared': ^1.0.0 - '@ice/types': ^1.0.0 acorn-walk: ^8.2.0 chalk: ^4.0.0 consola: ^2.15.3 @@ -950,18 +948,18 @@ importers: regenerator-runtime: 0.11.1 sax: 1.2.4 devDependencies: - '@ice/types': link:../types + '@ice/app': link:../ice webpack: 5.74.0 packages/plugin-moment-locales: specifiers: - '@ice/types': ^1.0.0 + '@ice/app': ^3.0.0 devDependencies: - '@ice/types': link:../types + '@ice/app': link:../ice packages/plugin-pha: specifiers: - '@ice/types': ^1.0.0 + '@ice/app': ^3.0.0 chalk: ^4.0.0 consola: ^2.15.3 esbuild: ^0.14.51 @@ -975,7 +973,7 @@ importers: humps: 2.0.1 lodash.clonedeep: 4.5.0 devDependencies: - '@ice/types': link:../types + '@ice/app': link:../ice esbuild: 0.14.54 webpack: 5.74.0_esbuild@0.14.54 webpack-dev-server: 4.11.1_webpack@5.74.0 @@ -984,15 +982,15 @@ importers: specifiers: '@babel/core': ^7.0.0 '@babel/plugin-proposal-export-default-from': ^7.18.9 + '@ice/app': ^3.0.0 '@ice/bundles': ^0.1.0 - '@ice/types': ^1.0.0 - '@types/webpack': ^5.28.0 babel-plugin-transform-jsx-stylesheet: 1.0.6 consola: ^2.15.3 css: ^2.2.1 lodash.merge: ^4.6.2 rax-compat: ^0.1.0 stylesheet-loader: ^0.9.1 + webpack: ^5.73.0 dependencies: '@babel/core': 7.19.3 '@babel/plugin-proposal-export-default-from': 7.18.10_@babel+core@7.19.3 @@ -1004,12 +1002,13 @@ importers: rax-compat: link:../rax-compat stylesheet-loader: 0.9.1 devDependencies: - '@ice/types': link:../types - '@types/webpack': 5.28.0 + '@ice/app': link:../ice + webpack: 5.74.0 packages/plugin-request: specifiers: - '@ice/types': ^1.0.0 + '@ice/app': ^3.0.0 + '@ice/runtime': ^1.0.0 '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 ahooks: ^3.0.0 @@ -1019,15 +1018,17 @@ importers: ahooks: 3.7.1 axios: 0.27.2 devDependencies: - '@ice/types': link:../types + '@ice/app': link:../ice + '@ice/runtime': link:../runtime '@types/react': 18.0.21 '@types/react-dom': 18.0.6 regenerator-runtime: 0.13.9 packages/plugin-store: specifiers: + '@ice/app': ^3.0.0 + '@ice/runtime': ^1.0.0 '@ice/store': ^2.0.3 - '@ice/types': ^1.0.0 '@types/micromatch': ^4.0.2 '@types/react': ^18.0.0 '@types/react-dom': ^18.0.0 @@ -1041,7 +1042,8 @@ importers: fast-glob: 3.2.12 micromatch: 4.0.5 devDependencies: - '@ice/types': link:../types + '@ice/app': link:../ice + '@ice/runtime': link:../runtime '@types/micromatch': 4.0.2 '@types/react': 18.0.21 '@types/react-dom': 18.0.6 @@ -1083,7 +1085,6 @@ importers: packages/runtime: specifiers: '@ice/jsx-runtime': ^0.1.0 - '@ice/types': ^1.0.0 '@types/react': ^18.0.8 '@types/react-dom': ^18.0.3 history: ^5.3.0 @@ -1093,7 +1094,6 @@ importers: regenerator-runtime: ^0.13.9 dependencies: '@ice/jsx-runtime': link:../jsx-runtime - '@ice/types': link:../types history: 5.3.0 react-router-dom: 6.4.1_biqbaboplfbrettd7655fr4n2y devDependencies: @@ -1111,50 +1111,11 @@ importers: packages/style-import: specifiers: - '@ice/types': ^1.0.0 es-module-lexer: ^1.0.2 magic-string: ^0.26.2 dependencies: es-module-lexer: 1.0.3 magic-string: 0.26.4 - devDependencies: - '@ice/types': link:../types - - packages/types: - specifiers: - '@ice/route-manifest': ^1.0.0 - '@swc/core': 1.3.3 - build-scripts: ^2.0.0-26 - esbuild: ^0.14.51 - eslint: ^8.14.0 - eslint-webpack-plugin: 3.1.1 - fork-ts-checker-webpack-plugin: 7.2.6 - history: ^5.3.0 - react: ^18.0.0 - react-dom: ^18.2.0 - react-router-dom: ^6.2.2 - terser: ^5.12.1 - typescript: ^4.6.4 - unplugin: ^0.9.5 - webpack: ^5.73.0 - webpack-dev-server: ^4.7.4 - devDependencies: - '@ice/route-manifest': link:../route-manifest - '@swc/core': 1.3.3 - build-scripts: 2.0.0-26 - esbuild: 0.14.54 - eslint: 8.24.0 - eslint-webpack-plugin: 3.1.1_j6jdqc6yj4dakyrvwvnzxinrfq - fork-ts-checker-webpack-plugin: 7.2.6_qqxisngxjbp7lstdk7boexbu3e - history: 5.3.0 - react: 18.2.0 - react-dom: 18.2.0_react@18.2.0 - react-router-dom: 6.4.1_biqbaboplfbrettd7655fr4n2y - terser: 5.15.0 - typescript: 4.8.4 - unplugin: 0.9.6 - webpack: 5.74.0_erwzf5wtj3ezvtz6x57nwwsumu - webpack-dev-server: 4.11.1_webpack@5.74.0 packages/webpack-config: specifiers: @@ -1162,11 +1123,9 @@ importers: '@ice/swc-plugin-keep-export': 0.1.2 '@ice/swc-plugin-keep-platform': 0.1.1 '@ice/swc-plugin-remove-export': 0.1.1 - '@ice/types': ^1.0.0 '@rollup/pluginutils': ^4.2.0 '@swc/core': 1.3.3 browserslist: ^4.19.3 - build-scripts: ^2.0.0-26 consola: ^2.15.3 esbuild: ^0.14.51 fast-glob: ^3.2.11 @@ -1183,8 +1142,6 @@ importers: consola: 2.15.3 fast-glob: 3.2.12 devDependencies: - '@ice/types': link:../types - build-scripts: 2.0.0-26 esbuild: 0.14.54 webpack: 5.74.0_erwzf5wtj3ezvtz6x57nwwsumu webpack-dev-server: 4.11.1_webpack@5.74.0 @@ -6111,19 +6068,6 @@ packages: - webpack-cli dev: true - /@types/webpack/5.28.0: - resolution: {integrity: sha512-8cP0CzcxUiFuA9xGJkfeVpqmWTk9nx6CWwamRGCj95ph1SmlRRk9KlCZ6avhCbZd4L68LvYT6l1kpdEnQXrF8w==} - dependencies: - '@types/node': 18.7.23 - tapable: 2.2.1 - webpack: 5.74.0 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack-cli - dev: true - /@types/ws/8.5.3: resolution: {integrity: sha512-6YOoWjruKj1uLf3INHH7D3qTXwFfEsg1kf3c0uDdSBJwfa/llkwIjrAGV7j7mVgGNbzTQ3HiHKKDXl6bJPD97w==} dependencies: @@ -7437,6 +7381,7 @@ packages: npmlog: 4.1.2 picocolors: 1.0.0 semver: 7.3.7 + dev: false /builtin-modules/3.3.0: resolution: {integrity: sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==} @@ -16209,6 +16154,7 @@ packages: react: 18.2.0 react-dom: 18.2.0_react@18.2.0 react-router: 6.4.1_react@18.2.0 + dev: false /react-router/5.3.3_react@17.0.2: resolution: {integrity: sha512-mzQGUvS3bM84TnbtMYR8ZjKnuPJ71IjSzR+DE6UkUqvN4czWIqEs17yLL8xkAycv4ev0AiN+IGrWu88vJs/p2w==} @@ -19545,4 +19491,4 @@ packages: engines: {node: '>=10'} /zwitch/1.0.5: - resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==} \ No newline at end of file + resolution: {integrity: sha512-V50KMwwzqJV0NpZIZFwfOD5/lyny3WlSzRiXgA0G7VUnRlqttta1L6UQIHzd6EuBY/cHGfwTIck7w1yH6Q5zUw==} diff --git a/tsconfig.json b/tsconfig.json deleted file mode 100644 index f8eb00900..000000000 --- a/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "files": [], - "references": [ - { "path": "packages/runtime" }, - { "path": "packages/bundles" }, - { "path": "packages/route-manifest" }, - { "path": "packages/types" }, - { "path": "packages/webpack-config" }, - { "path": "packages/ice" }, - { "path": "packages/plugin-auth" }, - { "path": "packages/plugin-pha" }, - { "path": "packages/plugin-fusion" }, - { "path": "packages/miniapp-runtime" }, - { "path": "packages/shared" }, - { "path": "packages/plugin-antd" }, - { "path": "packages/plugin-rax-compat" } - ] -} diff --git a/website/docs/guide/plugins/plugin-dev.md b/website/docs/guide/plugins/plugin-dev.md index 2dce02d8b..a1fafcd4e 100644 --- a/website/docs/guide/plugins/plugin-dev.md +++ b/website/docs/guide/plugins/plugin-dev.md @@ -17,7 +17,7 @@ ice.js 提供了插件机制,在提供丰富的框架能力的基础上也可 ice.js 插件本质是一个 JS 模块,官方推荐以 TS 进行开发以获得良好的类型提示: ```ts -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; interface PluginOptions { id: string; @@ -40,7 +40,7 @@ export default plugin; 假设在项目根目录下有一个自定义插件 `my-plugin`: ```ts title="my-plugin.ts" -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; const plugin: Plugin = () => ({ name: 'my-plugin', @@ -108,7 +108,7 @@ export default defineConfig({ ```ts -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; const plugin: Plugin = () => ({ name: '@ice/my-plugin', @@ -125,7 +125,7 @@ export default plugin; ```tsx -import type { RuntimePlugin } from '@ice/types'; +import type { RuntimePlugin } from '@ice/app/esm/types'; const runtime: RuntimePlugin = async ({ appContext }) => { console.log(appContext); @@ -447,7 +447,7 @@ export default () => ({ 插件运行时可以定制框架的运行时能力: ```ts -import type { Plugin } from '@ice/types'; +import type { Plugin } from '@ice/app/esm/types'; const plugin: Plugin = () => ({ name: 'plugin-name' runtime: '/absolute/path/to/runtime', @@ -459,7 +459,7 @@ export default plugin; 框架运行时指向的文件地址为一个 JS 模块,源码阶段推荐用 TS 进行开发: ```ts -import type { RuntimePlugin } from '@ice/types'; +import type { RuntimePlugin } from '@ice/app/esm/types'; const runtime: RuntimePlugin = () => {}; export default runtime; From 0f3dfe45f54ec834016c1f4b737efb4e8f4a8178 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= Date: Wed, 2 Nov 2022 11:02:28 +0800 Subject: [PATCH 02/22] fix: generate default loaders (#654) --- packages/ice/templates/exports/data-loader.ts.ejs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/ice/templates/exports/data-loader.ts.ejs b/packages/ice/templates/exports/data-loader.ts.ejs index 5cd8b8e00..e3554b974 100644 --- a/packages/ice/templates/exports/data-loader.ts.ejs +++ b/packages/ice/templates/exports/data-loader.ts.ejs @@ -3,7 +3,12 @@ import { dataLoader } from '@ice/runtime'; <% if(dataLoaderImport.imports) {-%><%-dataLoaderImport.imports%><% } -%> +<% if (loaders) {-%> <%- loaders %> +<% } else { -%> +const loaders = {}; +<% } -%> + <% if(hasExportAppData) {-%>loaders['__app'] = getAppData;<% } -%> <% if(!dataLoaderImport.imports) {-%> From cd30e8363ac4d9cf22c2b776ecad9832eb3e2627 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= Date: Wed, 2 Nov 2022 11:31:28 +0800 Subject: [PATCH 03/22] fix: load data without matched ids (#656) --- packages/runtime/src/dataLoader.ts | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/packages/runtime/src/dataLoader.ts b/packages/runtime/src/dataLoader.ts index a3bdc6a88..8b2914f18 100644 --- a/packages/runtime/src/dataLoader.ts +++ b/packages/runtime/src/dataLoader.ts @@ -96,18 +96,15 @@ async function load(id: string, loader: GetData) { * Get loaders by config of loaders. */ function getLoaders(loadersConfig: LoadersConfig, fetcher: Function): Loaders { - const context = (window as any).__ICE_APP_CONTEXT__ || {}; - const matchedIds = context.matchedIds || []; - const loaders: Loaders = {}; - matchedIds.forEach(id => { - const loaderConfig = loadersConfig[id]; - if (loaderConfig) { - // If getData is an object, it is wrapped with a function. - loaders[id] = typeof loaderConfig === 'function' ? loadersConfig[id] : () => { - return fetcher(loaderConfig); - }; - } + + Object.keys(loadersConfig).forEach(id => { + const loader = loadersConfig[id]; + + // If getData is an object, it is wrapped with a function. + loaders[id] = typeof loader === 'function' ? loader : () => { + return fetcher(loader); + }; }); return loaders; From 821af2dd8a9b64459bc69657bbcd845cb2ed187f Mon Sep 17 00:00:00 2001 From: luhc228 <44047106+luhc228@users.noreply.github.com> Date: Wed, 2 Nov 2022 11:37:35 +0800 Subject: [PATCH 04/22] feat: web-worker example (#627) * docs: refactor assets * feat: web-worker example --- examples/with-web-worker/ice.config.mts | 3 ++ examples/with-web-worker/package.json | 21 +++++++++++++ examples/with-web-worker/src/app.ts | 3 ++ examples/with-web-worker/src/document.tsx | 22 ++++++++++++++ examples/with-web-worker/src/pages/index.tsx | 25 +++++++++++++++ examples/with-web-worker/src/utils/pi.ts | 9 ++++++ examples/with-web-worker/src/worker.ts | 6 ++++ examples/with-web-worker/tsconfig.json | 25 +++++++++++++++ pnpm-lock.yaml | 31 +++++++++++++++++-- website/docs/guide/basic/assets.md | 32 +++----------------- 10 files changed, 147 insertions(+), 30 deletions(-) create mode 100644 examples/with-web-worker/ice.config.mts create mode 100644 examples/with-web-worker/package.json create mode 100644 examples/with-web-worker/src/app.ts create mode 100644 examples/with-web-worker/src/document.tsx create mode 100644 examples/with-web-worker/src/pages/index.tsx create mode 100644 examples/with-web-worker/src/utils/pi.ts create mode 100644 examples/with-web-worker/src/worker.ts create mode 100644 examples/with-web-worker/tsconfig.json diff --git a/examples/with-web-worker/ice.config.mts b/examples/with-web-worker/ice.config.mts new file mode 100644 index 000000000..129fcfa67 --- /dev/null +++ b/examples/with-web-worker/ice.config.mts @@ -0,0 +1,3 @@ +import { defineConfig } from '@ice/app'; + +export default defineConfig({}); diff --git a/examples/with-web-worker/package.json b/examples/with-web-worker/package.json new file mode 100644 index 000000000..8f6af4a3b --- /dev/null +++ b/examples/with-web-worker/package.json @@ -0,0 +1,21 @@ +{ + "name": "with-web-worker", + "version": "1.0.0", + "scripts": { + "start": "ice start", + "build": "ice build" + }, + "description": "", + "author": "", + "license": "MIT", + "dependencies": { + "@ice/runtime": "workspace:*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "devDependencies": { + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@ice/app": "workspace:*" + } +} \ No newline at end of file diff --git a/examples/with-web-worker/src/app.ts b/examples/with-web-worker/src/app.ts new file mode 100644 index 000000000..c1664902e --- /dev/null +++ b/examples/with-web-worker/src/app.ts @@ -0,0 +1,3 @@ +import { defineAppConfig } from 'ice'; + +export default defineAppConfig({}); diff --git a/examples/with-web-worker/src/document.tsx b/examples/with-web-worker/src/document.tsx new file mode 100644 index 000000000..e6753222f --- /dev/null +++ b/examples/with-web-worker/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-web-worker/src/pages/index.tsx b/examples/with-web-worker/src/pages/index.tsx new file mode 100644 index 000000000..3cbb98bd4 --- /dev/null +++ b/examples/with-web-worker/src/pages/index.tsx @@ -0,0 +1,25 @@ +import { useEffect, useRef, useCallback } from 'react'; + +export default function Index() { + const workerRef = useRef<Worker>(); + + useEffect(() => { + workerRef.current = new Worker(new URL('../worker.ts', import.meta.url)); + workerRef.current.onmessage = (event: MessageEvent<number>) => + alert(`WebWorker Response => ${event.data}`); + return () => { + workerRef.current && workerRef.current.terminate(); + }; + }, []); + + const handleWork = useCallback(async () => { + workerRef.current && workerRef.current.postMessage(100000); + }, []); + + return ( + <> + <p>Do work in a WebWorker!</p> + <button onClick={handleWork}>Calculate PI</button> + </> + ); +} diff --git a/examples/with-web-worker/src/utils/pi.ts b/examples/with-web-worker/src/utils/pi.ts new file mode 100644 index 000000000..d1d91e4c4 --- /dev/null +++ b/examples/with-web-worker/src/utils/pi.ts @@ -0,0 +1,9 @@ +// https://stackoverflow.com/a/39575124 +export default function pi(n: number) { + let v = 0; + for (let i = 1; i <= n; i += 4) { + // increment by 4 + v += 1 / i - 1 / (i + 2); // add the value of the series + } + return 4 * v; // apply the factor at last +} diff --git a/examples/with-web-worker/src/worker.ts b/examples/with-web-worker/src/worker.ts new file mode 100644 index 000000000..0b4367830 --- /dev/null +++ b/examples/with-web-worker/src/worker.ts @@ -0,0 +1,6 @@ +// This is a module worker, so we can use imports (in the browser too!) +import pi from './utils/pi'; + +addEventListener('message', (event: MessageEvent<number>) => { + postMessage(pi(event.data)); +}); diff --git a/examples/with-web-worker/tsconfig.json b/examples/with-web-worker/tsconfig.json new file mode 100644 index 000000000..6f2571086 --- /dev/null +++ b/examples/with-web-worker/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "module": "ESNext", + "target": "ESNext", + "lib": ["DOM", "ESNext", "DOM.Iterable"], + "jsx": "react-jsx", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": false, + "importHelpers": true, + "strictNullChecks": true, + "suppressImplicitAnyIndexErrors": true, + "skipLibCheck": true, + "paths": { + "@/*": ["./src/*"], + "ice": [".ice"] + } + }, + "include": ["src", ".ice"], + "exclude": ["build"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 36175fd9f..b990102bb 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -526,6 +526,23 @@ importers: typescript: 4.8.4 vitest: 0.15.2_jsdom@20.0.0 + examples/with-web-worker: + specifiers: + '@ice/app': workspace:* + '@ice/runtime': workspace:* + '@types/react': ^18.0.0 + '@types/react-dom': ^18.0.0 + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + '@ice/runtime': link:../../packages/runtime + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + devDependencies: + '@ice/app': link:../../packages/ice + '@types/react': 18.0.21 + '@types/react-dom': 18.0.6 + packages/appear: specifiers: react: ^18.0.0 @@ -3758,7 +3775,7 @@ packages: peerDependencies: react: '*' dependencies: - '@types/react': 17.0.50 + '@types/react': 18.0.21 prop-types: 15.8.1 react: 17.0.2 @@ -4825,6 +4842,7 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] requiresBuild: true dev: false optional: true @@ -4834,6 +4852,7 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] requiresBuild: true dev: false optional: true @@ -4843,6 +4862,7 @@ packages: engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] requiresBuild: true dev: false optional: true @@ -4852,6 +4872,7 @@ packages: engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] requiresBuild: true dev: false optional: true @@ -5443,6 +5464,7 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [glibc] requiresBuild: true optional: true @@ -5451,6 +5473,7 @@ packages: engines: {node: '>=10'} cpu: [arm64] os: [linux] + libc: [musl] requiresBuild: true optional: true @@ -5459,6 +5482,7 @@ packages: engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [glibc] requiresBuild: true optional: true @@ -5467,6 +5491,7 @@ packages: engines: {node: '>=10'} cpu: [x64] os: [linux] + libc: [musl] requiresBuild: true optional: true @@ -5960,14 +5985,14 @@ packages: resolution: {integrity: sha512-kpqnYK4wcdm5UaWI3fLcELopqLrHgLqNsdpHauzlQktfkHL3npOSwtj1Uz9oKBAzs7lFtVkV8j83voAz2D8fhw==} dependencies: '@types/history': 4.7.11 - '@types/react': 17.0.50 + '@types/react': 18.0.21 '@types/react-router': 5.1.19 /@types/react-router/5.1.19: resolution: {integrity: sha512-Fv/5kb2STAEMT3wHzdKQK2z8xKq38EDIGVrutYLmQVVLe+4orDFquU52hQrULnEHinMKv9FSA6lf9+uNT1ITtA==} dependencies: '@types/history': 4.7.11 - '@types/react': 17.0.50 + '@types/react': 18.0.21 /@types/react/17.0.50: resolution: {integrity: sha512-ZCBHzpDb5skMnc1zFXAXnL3l1FAdi+xZvwxK+PkglMmBrwjpp9nKaWuEvrGnSifCJmBFGxZOOFuwC6KH/s0NuA==} diff --git a/website/docs/guide/basic/assets.md b/website/docs/guide/basic/assets.md index 3aa35f44a..36ebfebce 100644 --- a/website/docs/guide/basic/assets.md +++ b/website/docs/guide/basic/assets.md @@ -5,7 +5,7 @@ order: 7 ice.js 内置了大量规则处理静态资源,一般情况下开发者无需设置资源的处理方式,而对于一些特殊的处理规则框架同样给出了便捷方式和指引 -# 基础规则 +## 基础规则 框架内置了针对以下资源的处理: @@ -38,11 +38,11 @@ function Home() { 如果资源尺寸小于 8kb,则进行 base64 转码并内联到脚本或样式文件中。 -# 指定处理规则 +## 指定处理规则 对于内置规则不满足特定场景的情况下,框架提供了便捷的方式对资源进行处理 -## URL 引入 +### URL 引入 除基础规则中指定资源外,如果还希望通过资源地址的方式进行资源处理的,可以通过如下方式进行指定: @@ -53,7 +53,7 @@ CSS.paintWorklet.addModule(workletURL); `?url` 等同于为指定资源指定 url-loader -## 文件内容引入 +### 文件内容引入 通过 `?raw` 后缀声明将资源作为字符串引入: @@ -63,29 +63,7 @@ import txtContent from './text.txt?raw'; `?raw` 等同于为指定资源指定 raw-loader -## Worker 引入 - -脚本可以通过指定后缀引入为 web worker: - -```jsx -import Worker from './worker.js?worker' -``` - -`?worker` 等同于为指定资源指定 worker-loader - -```jsx -import Worker from './worker.js?sharedworker' -``` - -`?sharedworker` 等同于为指定资源指定 worker-loader,并指定 worker 类型为 SharedWorker - -```jsx -import Worker from './worker.js?worker&inline' -``` - -`?worker&inline`等同于为指定资源指定 worker-loader,并指定配置 `{ inline: 'fallback' }` - -# public 目录 +## public 目录 `public/` 目录作为框架默认的静态资源目录,不被构建工具进行编译的资源都可以放在该目录下。 From b9adc4898df117be440064eada1260518dc36db6 Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Wed, 2 Nov 2022 11:46:58 +0800 Subject: [PATCH 05/22] fix: webpack instance of compiled bundle (#655) * fix: webpack instance of compiled bundle * chore: export type form compiled bundles --- packages/ice/src/commands/build.ts | 3 ++- packages/ice/src/types/userConfig.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/ice/src/commands/build.ts b/packages/ice/src/commands/build.ts index 5955e95af..a591c07cd 100644 --- a/packages/ice/src/commands/build.ts +++ b/packages/ice/src/commands/build.ts @@ -1,7 +1,7 @@ import consola from 'consola'; import { getWebpackConfig } from '@ice/webpack-config'; import type { Context, TaskConfig } from 'build-scripts'; -import webpack from 'webpack'; +import webpack from '@ice/bundles/compiled/webpack/index.js'; import type { StatsError, Stats } from 'webpack'; import type { Config } from '@ice/webpack-config/esm/types'; import type ora from '@ice/bundles/compiled/ora/index.js'; @@ -26,6 +26,7 @@ const build = async ( const webpackConfigs = taskConfigs.map(({ config }) => getWebpackConfig({ config, rootDir, + // @ts-expect-error fix type error of compiled webpack webpack, runtimeTmpDir: RUNTIME_TMP_DIR, })); diff --git a/packages/ice/src/types/userConfig.ts b/packages/ice/src/types/userConfig.ts index db500e638..3a12d04f6 100644 --- a/packages/ice/src/types/userConfig.ts +++ b/packages/ice/src/types/userConfig.ts @@ -1,6 +1,6 @@ import type { DefineRouteFunction } from '@ice/route-manifest'; import type { PluginList } from 'build-scripts'; -import type { UnpluginOptions } from 'unplugin'; +import type { UnpluginOptions } from '@ice/bundles/compiled/unplugin/index.js'; import type { Config, ModifyWebpackConfig, MinimizerOptions } from '@ice/webpack-config/esm/types'; import type { OverwritePluginAPI } from './plugin'; From 7bd4f2f71c3df70514047ef5d7a79e569e4ef0d8 Mon Sep 17 00:00:00 2001 From: luhc228 <44047106+luhc228@users.noreply.github.com> Date: Wed, 2 Nov 2022 14:07:51 +0800 Subject: [PATCH 06/22] fix: plugin-store will transform image (#639) * fix: plugin-store will transform image * feat: use regexp to filter module id --- examples/with-store/src/pages/ice.png | Bin 0 -> 36061 bytes examples/with-store/src/pages/index.tsx | 2 ++ examples/with-store/src/typings.d.ts | 1 + packages/plugin-store/src/index.ts | 6 +++++- 4 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 examples/with-store/src/pages/ice.png create mode 100644 examples/with-store/src/typings.d.ts diff --git a/examples/with-store/src/pages/ice.png b/examples/with-store/src/pages/ice.png new file mode 100644 index 0000000000000000000000000000000000000000..e5e98fac1e156e7fef7374d48be9749a7ec0ebe7 GIT binary patch literal 36061 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�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 C1#Ij9 literal 0 HcmV?d00001 diff --git a/examples/with-store/src/pages/index.tsx b/examples/with-store/src/pages/index.tsx index d7a1492f3..e8087126a 100644 --- a/examples/with-store/src/pages/index.tsx +++ b/examples/with-store/src/pages/index.tsx @@ -1,5 +1,6 @@ import { Link } from 'ice'; import pageStore from './store'; +import logo from './ice.png'; import appStore from '@/store'; function Home() { @@ -10,6 +11,7 @@ function Home() { <div id="username"> name: {userState.name} </div> + <img src={logo} alt="logo" height="100" width="100" /> <div> <button type="button" id="inc" onClick={() => countDispatcher.inc()}>+</button> <span id="count">{countState.count}</span> diff --git a/examples/with-store/src/typings.d.ts b/examples/with-store/src/typings.d.ts new file mode 100644 index 000000000..1f6ba4ffa --- /dev/null +++ b/examples/with-store/src/typings.d.ts @@ -0,0 +1 @@ +/// <reference types="@ice/app/types" /> diff --git a/packages/plugin-store/src/index.ts b/packages/plugin-store/src/index.ts index d95d30288..97a620e4a 100644 --- a/packages/plugin-store/src/index.ts +++ b/packages/plugin-store/src/index.ts @@ -72,7 +72,11 @@ function exportStoreProviderPlugin({ pageDir, resetPageState }: { pageDir: strin name: 'export-store-provider', enforce: 'post', transformInclude: (id) => { - return id.startsWith(pageDir.split(path.sep).join('/')) && !micromatch.isMatch(id, ignoreStoreFilePatterns); + return ( + /\.[jt]sx?$/i.test(id) && + id.startsWith(pageDir.split(path.sep).join('/')) && + !micromatch.isMatch(id, ignoreStoreFilePatterns) + ); }, transform: async (source, id) => { const pageStorePath = getPageStorePath(id); From c43fcb91a61ed9bea583e05d96c4175ea4d8096b Mon Sep 17 00:00:00 2001 From: luhc228 <44047106+luhc228@users.noreply.github.com> Date: Wed, 2 Nov 2022 15:03:14 +0800 Subject: [PATCH 07/22] refactor: app provider (#644) * refactor: app Provider * feat: add example * fix: example warning * fix: AppProvider to AppRuntimeProvider * feat: miniapp AppRuntimeProvider * fix: miniapp provider order * chore: remove type --- examples/basic-project/src/pages/index.tsx | 16 +------- examples/basic-project/src/pages/layout.tsx | 4 +- examples/with-store/src/pages/index.tsx | 6 ++- examples/with-store/src/pages/login.tsx | 15 ++++++++ packages/miniapp-runtime/src/app/App.tsx | 11 +----- .../miniapp-runtime/src/app/runClientApp.tsx | 30 +++++---------- packages/runtime/src/App.tsx | 6 +-- packages/runtime/src/runClientApp.tsx | 37 +++++++++---------- packages/runtime/src/runServerApp.tsx | 19 +++++----- 9 files changed, 63 insertions(+), 81 deletions(-) create mode 100644 examples/with-store/src/pages/login.tsx diff --git a/examples/basic-project/src/pages/index.tsx b/examples/basic-project/src/pages/index.tsx index 23dd5623f..0f35f9bff 100644 --- a/examples/basic-project/src/pages/index.tsx +++ b/examples/basic-project/src/pages/index.tsx @@ -1,5 +1,5 @@ import { Suspense, lazy } from 'react'; -import { Link, useData, useAppData, useConfig, ClientOnly, useMounted } from 'ice'; +import { Link, useData, useAppData, useConfig } from 'ice'; // not recommended but works import { useAppContext } from '@ice/runtime'; import { useRequest } from 'ahooks'; @@ -16,7 +16,6 @@ export default function Home(props) { const appData = useAppData<AppData>(); const data = useData(); const config = useConfig(); - const mounted = useMounted(); if (typeof window !== 'undefined') { console.log('render Home', props); @@ -42,19 +41,6 @@ export default function Home(props) { <div>userInfo: {JSON.stringify(userInfo)}</div> <div>data from: <span id="data-from">{data.from}</span></div> </div> - <p> - <div>{mounted ? 'Client' : 'Server'}</div> - <ClientOnly> - {() => { - const PageUrl = lazy(() => import('@/components/PageUrl')); - return ( - <Suspense> - <PageUrl /> - </Suspense> - ); - }} - </ClientOnly> - </p> </> ); } diff --git a/examples/basic-project/src/pages/layout.tsx b/examples/basic-project/src/pages/layout.tsx index 58dcf720e..5fc650047 100644 --- a/examples/basic-project/src/pages/layout.tsx +++ b/examples/basic-project/src/pages/layout.tsx @@ -1,6 +1,6 @@ import { Outlet, useData, useConfig } from 'ice'; -export default () => { +export default function Layout() { const data = useData(); const config = useConfig(); @@ -12,7 +12,7 @@ export default () => { <Outlet /> </div> ); -}; +} export function getConfig() { return { diff --git a/examples/with-store/src/pages/index.tsx b/examples/with-store/src/pages/index.tsx index e8087126a..81777d492 100644 --- a/examples/with-store/src/pages/index.tsx +++ b/examples/with-store/src/pages/index.tsx @@ -17,7 +17,11 @@ function Home() { <span id="count">{countState.count}</span> <button type="button" id="dec" onClick={() => countDispatcher.dec()}>-</button> </div> - <Link to="/blog">Blog</Link> + <> + <Link to="/blog">Blog</Link> + <br /> + <Link to="/login">Login</Link> + </> </> ); } diff --git a/examples/with-store/src/pages/login.tsx b/examples/with-store/src/pages/login.tsx new file mode 100644 index 000000000..e7a616cd8 --- /dev/null +++ b/examples/with-store/src/pages/login.tsx @@ -0,0 +1,15 @@ +import { history } from 'ice'; +import store from '@/store'; + +export default function Login() { + const [, userDispatcher] = store.useModel('user'); + + function login() { + userDispatcher.setState({ name: 'Hello' }); + history?.push('/'); + } + + return ( + <div onClick={() => login()} id="login-click">Click Me to Login</div> + ); +} diff --git a/packages/miniapp-runtime/src/app/App.tsx b/packages/miniapp-runtime/src/app/App.tsx index 63f170453..02cd81864 100644 --- a/packages/miniapp-runtime/src/app/App.tsx +++ b/packages/miniapp-runtime/src/app/App.tsx @@ -2,12 +2,7 @@ import React from 'react'; import { AppErrorBoundary, useAppContext } from '@ice/runtime'; import { AppWrapper } from './connect.js'; -interface Props { - AppProvider: React.ComponentType<any>; -} - -export default function App(props: Props) { - const { AppProvider } = props; +export default function App() { const { appConfig } = useAppContext(); const { strict, errorBoundary } = appConfig.app; const StrictMode = strict ? React.StrictMode : React.Fragment; @@ -16,9 +11,7 @@ export default function App(props: Props) { return ( <StrictMode> <ErrorBoundary> - <AppProvider> - <AppWrapper /> - </AppProvider> + <AppWrapper /> </ErrorBoundary> </StrictMode> ); diff --git a/packages/miniapp-runtime/src/app/runClientApp.tsx b/packages/miniapp-runtime/src/app/runClientApp.tsx index 6e9ff069e..ebc47796d 100644 --- a/packages/miniapp-runtime/src/app/runClientApp.tsx +++ b/packages/miniapp-runtime/src/app/runClientApp.tsx @@ -1,6 +1,6 @@ import React from 'react'; import type { - AppContext, RouteWrapperConfig, RunClientAppOptions, + AppContext, RunClientAppOptions, } from '@ice/runtime'; import { AppContextProvider, AppDataProvider, getAppData, getAppConfig, Runtime } from '@ice/runtime'; import App from './App.js'; @@ -37,43 +37,31 @@ async function render( runtime: Runtime, ) { const appContext = runtime.getAppContext(); - const { appConfig } = appContext; + const { appConfig, appData } = appContext; const render = runtime.getRender(); - const AppProvider = runtime.composeAppProvider() || React.Fragment; - const RouteWrappers = runtime.getWrappers(); + const AppRuntimeProvider = runtime.composeAppProvider() || React.Fragment; // TODO:支持设置 rootId (在 miniapp-runtime 中修改) render( document.getElementById(appConfig.app.rootId || 'app'), - <BrowserEntry - appContext={appContext} - AppProvider={AppProvider} - RouteWrappers={RouteWrappers} - />, + <AppDataProvider value={appData}> + <AppRuntimeProvider> + <BrowserEntry appContext={appContext} /> + </AppRuntimeProvider> + </AppDataProvider>, ); } interface BrowserEntryProps { appContext: AppContext; - AppProvider: React.ComponentType<any>; - RouteWrappers: RouteWrapperConfig[]; } function BrowserEntry({ appContext, - ...rest }: BrowserEntryProps) { - const { - appData, - } = appContext; - return ( <AppContextProvider value={appContext}> - <AppDataProvider value={appData}> - <App - {...rest} - /> - </AppDataProvider> + <App /> </AppContextProvider> ); } diff --git a/packages/runtime/src/App.tsx b/packages/runtime/src/App.tsx index e18936f4a..897ca2b1f 100644 --- a/packages/runtime/src/App.tsx +++ b/packages/runtime/src/App.tsx @@ -11,7 +11,6 @@ interface Props { location: Location; navigator: Navigator; static?: boolean; - AppProvider: React.ComponentType<any>; RouteWrappers: RouteWrapperConfig[]; AppRouter: React.ComponentType<AppRouterProps>; } @@ -22,7 +21,6 @@ export default function App(props: Props) { action, navigator, static: staticProp = false, - AppProvider, AppRouter, RouteWrappers, } = props; @@ -58,9 +56,7 @@ export default function App(props: Props) { return ( <StrictMode> <ErrorBoundary> - <AppProvider> - {element} - </AppProvider> + {element} </ErrorBoundary> </StrictMode> ); diff --git a/packages/runtime/src/runClientApp.tsx b/packages/runtime/src/runClientApp.tsx index 715053bb9..8326ecdae 100644 --- a/packages/runtime/src/runClientApp.tsx +++ b/packages/runtime/src/runClientApp.tsx @@ -116,9 +116,9 @@ interface RenderOptions { } async function render({ history, runtime }: RenderOptions) { const appContext = runtime.getAppContext(); - const { appConfig } = appContext; + const { appConfig, appData } = appContext; const render = runtime.getRender(); - const AppProvider = runtime.composeAppProvider() || React.Fragment; + const AppRuntimeProvider = runtime.composeAppProvider() || React.Fragment; const RouteWrappers = runtime.getWrappers(); const AppRouter = runtime.getAppRouter(); @@ -133,20 +133,22 @@ async function render({ history, runtime }: RenderOptions) { render( root, - <BrowserEntry - history={history} - appContext={appContext} - AppProvider={AppProvider} - RouteWrappers={RouteWrappers} - AppRouter={AppRouter} - />, + <AppDataProvider value={appData}> + <AppRuntimeProvider> + <BrowserEntry + history={history} + appContext={appContext} + RouteWrappers={RouteWrappers} + AppRouter={AppRouter} + /> + </AppRuntimeProvider> + </AppDataProvider>, ); } interface BrowserEntryProps { history: HashHistory | BrowserHistory | null; appContext: AppContext; - AppProvider: React.ComponentType<any>; RouteWrappers: RouteWrapperConfig[]; AppRouter: React.ComponentType<AppRouterProps>; } @@ -175,7 +177,6 @@ function BrowserEntry({ routesConfig: initialRoutesConfig, routeModules: initialRouteModules, basename, - appData, } = appContext; const [historyState, setHistoryState] = useState<HistoryState>({ @@ -229,14 +230,12 @@ function BrowserEntry({ return ( <AppContextProvider value={appContext}> - <AppDataProvider value={appData}> - <App - action={action} - location={location} - navigator={history} - {...rest} - /> - </AppDataProvider> + <App + action={action} + location={location} + navigator={history} + {...rest} + /> </AppContextProvider> ); } diff --git a/packages/runtime/src/runServerApp.tsx b/packages/runtime/src/runServerApp.tsx index 4c6db411b..a5f1099a4 100644 --- a/packages/runtime/src/runServerApp.tsx +++ b/packages/runtime/src/runServerApp.tsx @@ -250,7 +250,7 @@ async function renderServerEntry( const appContext = runtime.getAppContext(); const { appData, routePath } = appContext; const staticNavigator = createStaticNavigator(); - const AppProvider = runtime.composeAppProvider() || React.Fragment; + const AppRuntimeProvider = runtime.composeAppProvider() || React.Fragment; const RouteWrappers = runtime.getWrappers(); const AppRouter = runtime.getAppRouter(); @@ -260,20 +260,21 @@ async function renderServerEntry( location={location} navigator={staticNavigator} static - AppProvider={AppProvider} RouteWrappers={RouteWrappers} AppRouter={AppRouter} />, }; const element = ( - <AppContextProvider value={appContext}> - <AppDataProvider value={appData}> - <DocumentContextProvider value={documentContext}> - <Document pagePath={routePath} /> - </DocumentContextProvider> - </AppDataProvider> - </AppContextProvider> + <AppDataProvider value={appData}> + <AppRuntimeProvider> + <AppContextProvider value={appContext}> + <DocumentContextProvider value={documentContext}> + <Document pagePath={routePath} /> + </DocumentContextProvider> + </AppContextProvider> + </AppRuntimeProvider> + </AppDataProvider> ); const pipe = renderToNodeStream(element, false); From 60049661ba365a47ac40835bc11c8527237547ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9F=93=E9=99=8C=E5=90=8C=E5=AD=A6?= <answershuto@gmail.com> Date: Wed, 2 Nov 2022 16:22:11 +0800 Subject: [PATCH 08/22] docs: add addDataLoaderImport (#636) --- website/docs/guide/plugins/plugin-dev.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/website/docs/guide/plugins/plugin-dev.md b/website/docs/guide/plugins/plugin-dev.md index a1fafcd4e..db40eb8b3 100644 --- a/website/docs/guide/plugins/plugin-dev.md +++ b/website/docs/guide/plugins/plugin-dev.md @@ -408,6 +408,25 @@ export default () => ({ }); ``` +#### `addDataLoaderImport` + +向 ice.js 里注册 data-loader 的自定义发送方法,实现 `import { customFetch as fetcher } from 'custom-fetch';` 的能力: + +```ts +export default () => ({ + name: 'plugin-test', + setup: ({ generator }) => { + generator.addDataLoaderImport({ + source: 'custom-fetch', + alias: { + customFetch: 'fetcher', + }, + specifier: ['customFetch'], + }); + }, +}); +``` + ### `watch` 支持统一的 watch 服务 From 4987812ffe5753a998a1f57a1e82d576c937708e Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Thu, 3 Nov 2022 19:17:04 +0800 Subject: [PATCH 09/22] fix: duplicate assets in document output (#646) * fix: duplicate assets in document output * fix: add test case * chore: typo --- .../core/{entry.client.ts.ejs => entry.client.tsx.ejs} | 4 +++- packages/runtime/src/Document.tsx | 10 +++++++++- packages/webpack-config/src/index.ts | 2 +- tests/integration/basic-project.test.ts | 3 ++- 4 files changed, 15 insertions(+), 4 deletions(-) rename packages/ice/templates/core/{entry.client.ts.ejs => entry.client.tsx.ejs} (81%) diff --git a/packages/ice/templates/core/entry.client.ts.ejs b/packages/ice/templates/core/entry.client.tsx.ejs similarity index 81% rename from packages/ice/templates/core/entry.client.ts.ejs rename to packages/ice/templates/core/entry.client.tsx.ejs index bfee27acc..a5efb10a9 100644 --- a/packages/ice/templates/core/entry.client.ts.ejs +++ b/packages/ice/templates/core/entry.client.tsx.ejs @@ -10,7 +10,9 @@ const getRouterBasename = () => { const appConfig = getAppConfig(app); return appConfig?.router?.basename ?? '<%- basename %>' ?? ''; } - +// Add react fragment for split chunks of app. +// Otherwise chunk of route component will pack @ice/jsx-runtime and depend on framework bundle. +const App = <></>; runClientApp({ app, runtimeModules: { diff --git a/packages/runtime/src/Document.tsx b/packages/runtime/src/Document.tsx index 29690f616..ec675efc6 100644 --- a/packages/runtime/src/Document.tsx +++ b/packages/runtime/src/Document.tsx @@ -70,12 +70,20 @@ export function Scripts(props: React.ScriptHTMLAttributes<HTMLScriptElement>) { const pageAssets = getPageAssets(matches, assetsManifest); const entryAssets = getEntryAssets(assetsManifest); // Page assets need to be load before entry assets, so when call dynamic import won't cause duplicate js chunk loaded. - const scripts = pageAssets.concat(entryAssets).filter(path => path.indexOf('.js') > -1); + let scripts = pageAssets.concat(entryAssets).filter(path => path.indexOf('.js') > -1); if (assetsManifest.dataLoader) { scripts.unshift(`${assetsManifest.publicPath}${assetsManifest.dataLoader}`); } + // Unique scripts for duplicate chunks. + const jsSet = {}; + scripts = scripts.filter((script) => { + if (jsSet[script]) return false; + jsSet[script] = true; + return true; + }); + const matchedIds = matches.map(match => match.route.id); const routePath = getCurrentRoutePath(matches); const windowContext: WindowContext = { diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index 5370e4d23..3cfe0fcf7 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -48,7 +48,7 @@ function getEntry(rootDir: string, runtimeTmpDir: string) { })[0]; if (!entryFile) { // use generated file in template directory - entryFile = path.join(rootDir, runtimeTmpDir, 'entry.client.ts'); + entryFile = path.join(rootDir, runtimeTmpDir, 'entry.client.tsx'); } // const dataLoaderFile = path.join(rootDir, '.ice/data-loader.ts'); diff --git a/tests/integration/basic-project.test.ts b/tests/integration/basic-project.test.ts index 867c852b4..9b35e5f18 100644 --- a/tests/integration/basic-project.test.ts +++ b/tests/integration/basic-project.test.ts @@ -33,7 +33,8 @@ describe(`build ${example}`, () => { expect(bundleContent.includes('__IS_NODE__')).toBe(false); expect(fs.existsSync(path.join(__dirname, `../../examples/${example}/build/favicon.ico`))).toBe(true); expect(fs.existsSync(path.join(__dirname, `../../examples/${example}/build/js/data-loader.js`))).toBe(true); - + const jsonContent = fs.readFileSync(path.join(__dirname, `../../examples/${example}/build/assets-manifest.json`), 'utf-8'); + expect(JSON.parse(jsonContent).pages.about.includes('js/framework.js')).toBeFalsy(); const dataLoaderPath = path.join(__dirname, `../../examples/${example}/build/js/data-loader.js`); // should not contain react const dataLoaderContent = fs.readFileSync(dataLoaderPath, 'utf-8'); From c2d1d027b2ab43c82a91b9517dee7e18f577eedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= <shuilan.cj@taobao.com> Date: Fri, 4 Nov 2022 14:39:41 +0800 Subject: [PATCH 10/22] feat: support crossorigin (#649) * feat: support pass crossorigin * docs: cross origin loading * fix: config doc * docs: add link * Update config.md --- packages/ice/src/config.ts | 10 ++++++++++ packages/ice/src/types/userConfig.ts | 1 + website/docs/guide/basic/config.md | 17 +++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/packages/ice/src/config.ts b/packages/ice/src/config.ts index 194c8a469..fdc08fa93 100644 --- a/packages/ice/src/config.ts +++ b/packages/ice/src/config.ts @@ -329,6 +329,16 @@ const userConfig = [ config.splitChunks = splitChunks; }, }, + { + name: 'crossOriginLoading', + validation: 'boolean|string', + defaultValue: false, + setConfig: (config: Config, crossOriginLoading: UserConfig['crossOriginLoading']) => { + config.output = merge(config.output || {}, { + crossOriginLoading, + }); + }, + }, ]; const cliOption = [ diff --git a/packages/ice/src/types/userConfig.ts b/packages/ice/src/types/userConfig.ts index 3a12d04f6..da9b908f8 100644 --- a/packages/ice/src/types/userConfig.ts +++ b/packages/ice/src/types/userConfig.ts @@ -60,4 +60,5 @@ export interface UserConfig { syntaxFeatures?: SyntaxFeatures; splitChunks?: boolean; dataLoader?: boolean; + crossOriginLoading?: Config['output']['crossOriginLoading']; } diff --git a/website/docs/guide/basic/config.md b/website/docs/guide/basic/config.md index 083358606..2b89d8a98 100644 --- a/website/docs/guide/basic/config.md +++ b/website/docs/guide/basic/config.md @@ -55,6 +55,23 @@ export default defineConfig({ }); ``` +### crossOriginLoading + +- 类型:`false | 'anonymous' | 'use-credentials'` +- 默认值:`false` + +配置 + +```js +import { defineConfig } from '@ice/app'; + +export default defineConfig({ + crossOriginLoading: 'anonymous' +}); +``` + +指定 webpack 启用 [cross-origin](https://webpack.js.org/configuration/output/#outputcrossoriginloading) 去加载 chunk。 + ### define - 类型:`Record<string, string | boolean>` From 02226922186ffd24a5e84346077cff9ce84aab34 Mon Sep 17 00:00:00 2001 From: luhc228 <44047106+luhc228@users.noreply.github.com> Date: Fri, 4 Nov 2022 15:14:52 +0800 Subject: [PATCH 11/22] fix: still use cache when config is modified (#659) * fix: still use cache when config is modified * fix: test case * refactor: remove userConfigPath param --- packages/ice/src/commands/build.ts | 4 +++- packages/ice/src/commands/start.ts | 3 +++ packages/ice/src/createService.ts | 5 +++++ packages/webpack-config/src/index.ts | 5 +++-- 4 files changed, 14 insertions(+), 3 deletions(-) diff --git a/packages/ice/src/commands/build.ts b/packages/ice/src/commands/build.ts index a591c07cd..6c008d3ef 100644 --- a/packages/ice/src/commands/build.ts +++ b/packages/ice/src/commands/build.ts @@ -19,9 +19,10 @@ const build = async ( spinner: ora.Ora; getAppConfig: GetAppConfig; getRoutesConfig: GetRoutesConfig; + userConfigHash: string; }, ) => { - const { taskConfigs, serverCompiler, spinner, getAppConfig, getRoutesConfig } = options; + const { taskConfigs, serverCompiler, spinner, getAppConfig, getRoutesConfig, userConfigHash } = options; const { applyHook, rootDir } = context; const webpackConfigs = taskConfigs.map(({ config }) => getWebpackConfig({ config, @@ -29,6 +30,7 @@ const build = async ( // @ts-expect-error fix type error of compiled webpack webpack, runtimeTmpDir: RUNTIME_TMP_DIR, + userConfigHash, })); const outputDir = webpackConfigs[0].output.path; diff --git a/packages/ice/src/commands/start.ts b/packages/ice/src/commands/start.ts index 6ca70908f..5c9d45a37 100644 --- a/packages/ice/src/commands/start.ts +++ b/packages/ice/src/commands/start.ts @@ -32,6 +32,7 @@ const start = async ( spinner: ora.Ora; getAppConfig: GetAppConfig; getRoutesConfig: GetRoutesConfig; + userConfigHash: string; }, ) => { const { @@ -42,6 +43,7 @@ const start = async ( spinner, getAppConfig, getRoutesConfig, + userConfigHash, } = options; const { commandArgs, rootDir } = context; const { platform = WEB } = commandArgs; @@ -51,6 +53,7 @@ const start = async ( // @ts-expect-error fix type error of compiled webpack webpack, runtimeTmpDir: RUNTIME_TMP_DIR, + userConfigHash, })); const hooksAPI = { diff --git a/packages/ice/src/createService.ts b/packages/ice/src/createService.ts index 9cf2f33bb..b4049719f 100644 --- a/packages/ice/src/createService.ts +++ b/packages/ice/src/createService.ts @@ -7,6 +7,7 @@ import type { CommandArgs, CommandName } from 'build-scripts'; import type { Config } from '@ice/webpack-config/esm/types'; import type { AppConfig } from '@ice/runtime/esm/types'; import webpack from '@ice/bundles/compiled/webpack/index.js'; +import fg from 'fast-glob'; import type { DeclarationData } from './types/generator.js'; import type { PluginData, ExtendsPluginAPI } from './types/plugin.js'; import Generator from './service/runtimeGenerator.js'; @@ -29,6 +30,7 @@ import ServerCompileTask from './utils/ServerCompileTask.js'; import { getAppExportConfig, getRouteExportConfig } from './service/config.js'; import renderExportsTemplate from './utils/renderExportsTemplate.js'; import { getFileExports } from './service/analyze.js'; +import { getFileHash } from './utils/hash.js'; const require = createRequire(import.meta.url); const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -133,6 +135,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt // get userConfig after setup because of userConfig maybe modified by plugins const { userConfig } = ctx; const { routes: routesConfig, server, syntaxFeatures } = userConfig; + const userConfigHash = await getFileHash(path.join(rootDir, fg.sync(configFile, { cwd: rootDir })[0])); await setEnv(rootDir, commandArgs); const coreEnvKeys = getCoreEnvKeys(); @@ -237,6 +240,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt appConfig, devPath: (routePaths[0] || '').replace(/^[/\\]/, ''), spinner: buildSpinner, + userConfigHash, }); } else if (command === 'build') { return await build(ctx, { @@ -245,6 +249,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt taskConfigs, serverCompiler, spinner: buildSpinner, + userConfigHash, }); } else if (command === 'test') { return await test(ctx, { diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index 3cfe0fcf7..2159b97ba 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -33,6 +33,7 @@ interface GetWebpackConfigOptions { config: Config; webpack: typeof webpack; runtimeTmpDir: string; + userConfigHash: string; } type GetWebpackConfig = (options: GetWebpackConfigOptions) => Configuration; enum JSMinifier { @@ -59,7 +60,7 @@ function getEntry(rootDir: string, runtimeTmpDir: string) { }; } -const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeTmpDir }) => { +const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeTmpDir, userConfigHash }) => { const { mode, define = {}, @@ -257,7 +258,7 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT } as Configuration['optimization'], cache: { type: 'filesystem', - version: `${process.env.__ICE_VERSION__}|${JSON.stringify(config)}`, + version: `${process.env.__ICE_VERSION__}|${userConfigHash}`, buildDependencies: { config: [path.join(rootDir, 'package.json')] }, cacheDirectory: path.join(cacheDir, 'webpack'), }, From 3d704c9a61cb7b3340f43061d11ac3c3056c9a9a Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Fri, 4 Nov 2022 17:07:52 +0800 Subject: [PATCH 12/22] feat: config polyfill for bowsers support (#652) * feat: config polyfill for bowsers support * chore: optimize code * chore: lock * chore: test case * chore: test case * chore: comment --- packages/ice/package.json | 2 + packages/ice/src/config.ts | 7 ++++ packages/ice/src/createService.ts | 3 +- packages/ice/src/service/serverCompiler.ts | 2 + packages/ice/src/tasks/web/index.ts | 9 ++++- packages/ice/src/types/userConfig.ts | 1 + .../ice/templates/core/entry.client.tsx.ejs | 1 + packages/ice/tests/defineJestConfig.test.ts | 12 +++++- packages/ice/tests/defineVitestConfig.test.ts | 12 +++++- .../webpack-config/src/getCompilerPlugins.ts | 4 ++ packages/webpack-config/src/index.ts | 3 ++ packages/webpack-config/src/types.ts | 4 ++ .../src/unPlugins/compilation.ts | 37 ++++++++++++++++--- pnpm-lock.yaml | 15 ++++++++ website/docs/guide/basic/config.md | 11 ++++++ 15 files changed, 112 insertions(+), 11 deletions(-) diff --git a/packages/ice/package.json b/packages/ice/package.json index 8f2d7ccbd..e12f4614c 100644 --- a/packages/ice/package.json +++ b/packages/ice/package.json @@ -41,10 +41,12 @@ "@ice/route-manifest": "^1.0.0", "@ice/runtime": "^1.0.0", "@ice/webpack-config": "^1.0.0", + "@swc/helpers": "0.4.12", "address": "^1.1.2", "build-scripts": "^2.0.0-26", "chalk": "^4.0.0", "commander": "^9.0.0", + "core-js": "3.26.0", "consola": "^2.15.3", "cross-spawn": "^7.0.3", "detect-port": "^1.3.0", diff --git a/packages/ice/src/config.ts b/packages/ice/src/config.ts index fdc08fa93..4c9029964 100644 --- a/packages/ice/src/config.ts +++ b/packages/ice/src/config.ts @@ -94,6 +94,13 @@ const userConfig = [ return mergeDefaultValue(config, 'proxy', proxy); }, }, + { + name: 'polyfill', + validation: 'string|boolean', + setConfig: (config: Config, polyfill: UserConfig['polyfill']) => { + return mergeDefaultValue(config, 'polyfill', polyfill); + }, + }, { name: 'filename', validation: 'string', diff --git a/packages/ice/src/createService.ts b/packages/ice/src/createService.ts index b4049719f..a939d35d5 100644 --- a/packages/ice/src/createService.ts +++ b/packages/ice/src/createService.ts @@ -134,7 +134,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt // get userConfig after setup because of userConfig maybe modified by plugins const { userConfig } = ctx; - const { routes: routesConfig, server, syntaxFeatures } = userConfig; + const { routes: routesConfig, server, syntaxFeatures, polyfill } = userConfig; const userConfigHash = await getFileHash(path.join(rootDir, fg.sync(configFile, { cwd: rootDir })[0])); await setEnv(rootDir, commandArgs); @@ -172,6 +172,7 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt basename: platformTaskConfig.config.basename || '/', memoryRouter: platformTaskConfig.config.memoryRouter, hydrate: !csr, + importCoreJs: polyfill === 'entry', }); dataCache.set('routes', JSON.stringify(routesInfo)); dataCache.set('hasExportAppData', hasExportAppData ? 'true' : ''); diff --git a/packages/ice/src/service/serverCompiler.ts b/packages/ice/src/service/serverCompiler.ts index 5fc83e747..aae6cbfe8 100644 --- a/packages/ice/src/service/serverCompiler.ts +++ b/packages/ice/src/service/serverCompiler.ts @@ -68,6 +68,8 @@ export function createServerCompiler(options: Options) { const transformPlugins = getCompilerPlugins({ ...task.config, fastRefresh: false, + env: false, + polyfill: false, swcOptions, }, 'esbuild'); diff --git a/packages/ice/src/tasks/web/index.ts b/packages/ice/src/tasks/web/index.ts index e134eb1ee..2b0089a9a 100644 --- a/packages/ice/src/tasks/web/index.ts +++ b/packages/ice/src/tasks/web/index.ts @@ -17,8 +17,15 @@ const getWebTask = ({ rootDir, command, dataCache }): Config => { '@': path.join(rootDir, 'src'), // set alias for webpack/hot while webpack has been prepacked 'webpack/hot': '@ice/bundles/compiled/webpack/hot', - // Get absolute path of `regenerator-runtime`, so it's unnecessary to add it to project dependencies + // Get absolute path of `regenerator-runtime`, `@swc/helpers`, `core-js` + // so it's unnecessary to add it to project dependencies. 'regenerator-runtime': require.resolve('regenerator-runtime'), + '@swc/helpers': path.dirname( + require.resolve('@swc/helpers/package.json'), + ), + 'core-js': path.dirname( + require.resolve('core-js/package.json'), + ), }, swcOptions: { // getData is built by data-loader diff --git a/packages/ice/src/types/userConfig.ts b/packages/ice/src/types/userConfig.ts index da9b908f8..4a9559875 100644 --- a/packages/ice/src/types/userConfig.ts +++ b/packages/ice/src/types/userConfig.ts @@ -33,6 +33,7 @@ export interface UserConfig { externals?: Config['externals']; outputDir?: string; proxy?: Config['proxy']; + polyfill?: Config['polyfill']; filename?: string; webpack?: ModifyWebpackConfig; routes?: { diff --git a/packages/ice/templates/core/entry.client.tsx.ejs b/packages/ice/templates/core/entry.client.tsx.ejs index a5efb10a9..e04da6b6d 100644 --- a/packages/ice/templates/core/entry.client.tsx.ejs +++ b/packages/ice/templates/core/entry.client.tsx.ejs @@ -1,3 +1,4 @@ +<% if (importCoreJs) { -%>import 'core-js';<% } -%> import { runClientApp, getAppConfig } from '<%- iceRuntimePath %>'; import { commons, statics } from './runtimeModules'; import * as app from '@/app'; diff --git a/packages/ice/tests/defineJestConfig.test.ts b/packages/ice/tests/defineJestConfig.test.ts index 2640c78ed..6b16ae7e3 100644 --- a/packages/ice/tests/defineJestConfig.test.ts +++ b/packages/ice/tests/defineJestConfig.test.ts @@ -6,6 +6,14 @@ import { defineJestConfig } from '../src/test'; const __dirname = fileURLToPath(path.dirname(import.meta.url)); describe('defineJestConfig', () => { + const builtInAlias = [ + '^ice', + '^@/(.*)', + '^webpack/hot', + '^regenerator-runtime', + '^@swc/helpers/(.*)', + '^core-js/(.*)', + ]; beforeAll(() => { const spy = vi.spyOn(process, 'cwd'); spy.mockReturnValue(path.join(__dirname, '../../../examples/with-jest')); @@ -15,14 +23,14 @@ describe('defineJestConfig', () => { const jestConfigFn = defineJestConfig({}); const jestConfig = await jestConfigFn(); expect(Object.keys(jestConfig)).toStrictEqual(['moduleNameMapper']); - expect(Object.keys(jestConfig.moduleNameMapper as Record<string, string>)).toStrictEqual(['^ice', '^@/(.*)', '^webpack/hot', '^regenerator-runtime']); + expect(Object.keys(jestConfig.moduleNameMapper as Record<string, string>)).toStrictEqual(builtInAlias); }); it('get default config with function', async () => { const jestConfigFn = defineJestConfig(async () => { return {}; }); const jestConfig = await jestConfigFn(); expect(Object.keys(jestConfig)).toStrictEqual(['moduleNameMapper']); - expect(Object.keys(jestConfig.moduleNameMapper as Record<string, string>)).toStrictEqual(['^ice', '^@/(.*)', '^webpack/hot', '^regenerator-runtime']); + expect(Object.keys(jestConfig.moduleNameMapper as Record<string, string>)).toStrictEqual(builtInAlias); }); it('get config with custom object config', async () => { diff --git a/packages/ice/tests/defineVitestConfig.test.ts b/packages/ice/tests/defineVitestConfig.test.ts index 62db5efca..a6f300aa1 100644 --- a/packages/ice/tests/defineVitestConfig.test.ts +++ b/packages/ice/tests/defineVitestConfig.test.ts @@ -6,6 +6,14 @@ import { defineVitestConfig } from '../src/test'; const __dirname = fileURLToPath(path.dirname(import.meta.url)); describe('defineVitestConfig', () => { + const builtInAlias = [ + 'ice', + '@', + 'webpack/hot', + 'regenerator-runtime', + '@swc/helpers', + 'core-js', + ]; beforeAll(() => { const spy = vi.spyOn(process, 'cwd'); spy.mockReturnValue(path.join(__dirname, '../../../examples/with-vitest')); @@ -15,14 +23,14 @@ describe('defineVitestConfig', () => { const vitestConfigFn = defineVitestConfig({}); const vitestConfig = await vitestConfigFn({ command: 'serve', mode: 'test' }); expect(Object.keys(vitestConfig.resolve as Record<string, string>)).toStrictEqual(['alias']); - expect(Object.keys(vitestConfig.resolve?.alias as Record<string, string>)).toStrictEqual(['ice', '@', 'webpack/hot', 'regenerator-runtime']); + expect(Object.keys(vitestConfig.resolve?.alias as Record<string, string>)).toStrictEqual(builtInAlias); }); it('get default config with function', async () => { const vitestConfigFn = defineVitestConfig(() => ({})); const vitestConfig = await vitestConfigFn({ command: 'serve', mode: 'test' }); expect(Object.keys(vitestConfig.resolve as Record<string, string>)).toStrictEqual(['alias']); - expect(Object.keys(vitestConfig.resolve?.alias as Record<string, string>)).toStrictEqual(['ice', '@', 'webpack/hot', 'regenerator-runtime']); + expect(Object.keys(vitestConfig.resolve?.alias as Record<string, string>)).toStrictEqual(builtInAlias); }); it('get config with custom object config', async () => { diff --git a/packages/webpack-config/src/getCompilerPlugins.ts b/packages/webpack-config/src/getCompilerPlugins.ts index dc8c4fd95..cf3e59811 100644 --- a/packages/webpack-config/src/getCompilerPlugins.ts +++ b/packages/webpack-config/src/getCompilerPlugins.ts @@ -42,6 +42,8 @@ function getCompilerPlugins(config: Config, compiler: Compiler) { swcOptions, fastRefresh, cacheDir, + polyfill, + env, } = config; const compilerPlugins = []; @@ -61,6 +63,8 @@ function getCompilerPlugins(config: Config, compiler: Compiler) { compileIncludes, compileExcludes, swcOptions, + polyfill, + env, })); } diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index 2159b97ba..347cf1a2f 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -96,6 +96,7 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT optimization = {}, performance, enableCopyPlugin, + polyfill, } = config; const absoluteOutputDir = path.isAbsolute(outputDir) ? outputDir : path.join(rootDir, outputDir); const dev = mode !== 'production'; @@ -166,6 +167,8 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT compileIncludes, compileExcludes, swcOptions, + polyfill, + env: true, }); const webpackConfig = { mode, diff --git a/packages/webpack-config/src/types.ts b/packages/webpack-config/src/types.ts index 7d3be8445..9621387c2 100644 --- a/packages/webpack-config/src/types.ts +++ b/packages/webpack-config/src/types.ts @@ -107,6 +107,10 @@ export interface Config { proxy?: ProxyConfigArrayItem | ProxyConfigMap | ProxyConfigArray | undefined; + polyfill?: 'usage' | 'entry' | false; + // You can use `browserslist` to automatically configure supported browsers if set to be true. + env?: boolean; + compileIncludes?: (string | RegExp)[]; minify?: boolean | string; diff --git a/packages/webpack-config/src/unPlugins/compilation.ts b/packages/webpack-config/src/unPlugins/compilation.ts index 6d6df6e67..a0f6b9fd2 100644 --- a/packages/webpack-config/src/unPlugins/compilation.ts +++ b/packages/webpack-config/src/unPlugins/compilation.ts @@ -18,10 +18,22 @@ interface Options { compileExcludes?: RegExp[]; swcOptions?: Config['swcOptions']; cacheDir?: string; + polyfill?: Config['polyfill']; + env?: boolean; } const compilationPlugin = (options: Options): UnpluginOptions => { - const { sourceMap, mode, fastRefresh, compileIncludes = [], compileExcludes, swcOptions = {}, cacheDir } = options; + const { + sourceMap, + mode, + fastRefresh, + compileIncludes = [], + compileExcludes, + swcOptions = {}, + cacheDir, + polyfill, + env, + } = options; const { removeExportExprs, compilationConfig, keepPlatform, keepExports, getRoutePaths } = swcOptions; @@ -61,7 +73,7 @@ const compilationPlugin = (options: Options): UnpluginOptions => { sourceMaps: !!sourceMap, }; - const commonOptions = getJsxTransformOptions({ suffix, fastRefresh }); + const commonOptions = getJsxTransformOptions({ suffix, fastRefresh, polyfill, env }); // auto detect development mode if ( @@ -154,11 +166,15 @@ const compilationPlugin = (options: Options): UnpluginOptions => { interface GetJsxTransformOptions { suffix: JSXSuffix; fastRefresh: boolean; + polyfill: Config['polyfill']; + env: boolean; } function getJsxTransformOptions({ suffix, fastRefresh, + polyfill, + env, }: GetJsxTransformOptions) { const reactTransformConfig: ReactConfig = { refresh: fastRefresh, @@ -172,16 +188,27 @@ function getJsxTransformOptions({ react: reactTransformConfig, legacyDecorator: true, }, + // This option will greatly reduce your file size while bundling. + // This option depends on `@swc/helpers`. externalHelpers: false, }, module: { type: 'es6', noInterop: false, }, - env: { - loose: false, - }, }; + if (env) { + commonOptions.env = { + loose: false, + ...(polyfill ? { + mode: polyfill, + coreJs: '3.26', + } : {}), + }; + } else { + // Set target `es2022` for default transform when env is false. + commonOptions.jsc.target = 'es2022'; + } const syntaxFeatures = { dynamicImport: true, decorators: true, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b990102bb..32d8e7a97 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -714,6 +714,7 @@ importers: '@ice/route-manifest': ^1.0.0 '@ice/runtime': ^1.0.0 '@ice/webpack-config': ^1.0.0 + '@swc/helpers': 0.4.12 '@types/babel__generator': ^7.6.4 '@types/babel__traverse': ^7.17.1 '@types/cross-spawn': ^6.0.2 @@ -730,6 +731,7 @@ importers: chokidar: ^3.5.3 commander: ^9.0.0 consola: ^2.15.3 + core-js: 3.26.0 cross-spawn: ^7.0.3 detect-port: ^1.3.0 dotenv: ^16.0.0 @@ -763,11 +765,13 @@ importers: '@ice/route-manifest': link:../route-manifest '@ice/runtime': link:../runtime '@ice/webpack-config': link:../webpack-config + '@swc/helpers': 0.4.12 address: 1.2.1 build-scripts: 2.0.0-26 chalk: 4.1.2 commander: 9.4.0 consola: 2.15.3 + core-js: 3.26.0 cross-spawn: 7.0.3 detect-port: 1.5.1 dotenv: 16.0.2 @@ -5549,6 +5553,12 @@ packages: tslib: 2.4.0 dev: false + /@swc/helpers/0.4.12: + resolution: {integrity: sha512-R6RmwS9Dld5lNvwKlPn62+piU+WDG1sMfsnfJioXCciyko/gZ0DQ4Mqglhq1iGU1nQ/RcGkAwfMH+elMSkJH3Q==} + dependencies: + tslib: 2.4.0 + dev: false + /@swc/wasm/1.2.122: resolution: {integrity: sha512-sM1VCWQxmNhFtdxME+8UXNyPNhxNu7zdb6ikWpz0YKAQQFRGT5ThZgJrubEpah335SUToNg8pkdDF7ibVCjxbQ==} requiresBuild: true @@ -8064,6 +8074,11 @@ packages: resolution: {integrity: sha512-y1hvKXmPHvm5B7w4ln1S4uc9eV/O5+iFExSRUimnvIph11uaizFR8LFMdONN8hG3P2pipUfX4Y/fR8rAEtcHcQ==} requiresBuild: true + /core-js/3.26.0: + resolution: {integrity: sha512-+DkDrhoR4Y0PxDz6rurahuB+I45OsEUv8E1maPTB6OuHRohMMcznBq9TMpdpDMm/hUPob/mJJS3PqgbHpMTQgw==} + requiresBuild: true + dev: false + /core-util-is/1.0.2: resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} dev: false diff --git a/website/docs/guide/basic/config.md b/website/docs/guide/basic/config.md index 2b89d8a98..a1eedaba7 100644 --- a/website/docs/guide/basic/config.md +++ b/website/docs/guide/basic/config.md @@ -241,6 +241,17 @@ export default defineConfig({ }); ``` +### polyfill + +- 类型:`'usage' | 'entry' | false` +- 默认值:`false` + +框架提供了多种 polyfill 的方式,开发者可以按实际情况选择对应的设置: +- `usage` 按开发者使用的语法自动引入对应的 `polyfill`,适用于 `node_modules` 也进行编译的场景(一定程度上影响编译效率以及三方依赖二次编译造成的代码冗余) +- `entry` 自动引入 browser(浏览器)需要兼容的 `polyfill`,适用于 `node_modules` 依赖不进行编译的场景(可能存在大量未被使用的 `polyfill` 被引入) + +> 如果面向现代浏览器进行开发,大量 ES 语法均不需要引入 Polyfill,我们推荐不开启 `polyfill` 配置。如果你的代码或者三方依赖要求兼容到 IE 11 等浏览器,可以选择主动引入指定语法的 polyfill 或者开启 `polyfill` 配置。 + ### transform - 类型:`(code:string, id: string) => string | {code: string; map?: SourceMap | null;}` From 44277499a4283513c95b9f1fc0f0b372087148ae Mon Sep 17 00:00:00 2001 From: luhc228 <44047106+luhc228@users.noreply.github.com> Date: Mon, 7 Nov 2022 10:25:09 +0800 Subject: [PATCH 13/22] feat: read browsers config by postcss-preset-env (#664) --- packages/webpack-config/package.json | 1 - packages/webpack-config/src/config/css.ts | 8 +++----- packages/webpack-config/src/index.ts | 20 -------------------- packages/webpack-config/src/types.ts | 1 - pnpm-lock.yaml | 2 -- 5 files changed, 3 insertions(+), 29 deletions(-) diff --git a/packages/webpack-config/package.json b/packages/webpack-config/package.json index f96a66096..072eda323 100644 --- a/packages/webpack-config/package.json +++ b/packages/webpack-config/package.json @@ -21,7 +21,6 @@ "@swc/core": "1.3.3", "@ice/bundles": "^0.1.0", "@rollup/pluginutils": "^4.2.0", - "browserslist": "^4.19.3", "consola": "^2.15.3", "fast-glob": "^3.2.11" }, diff --git a/packages/webpack-config/src/config/css.ts b/packages/webpack-config/src/config/css.ts index 32c859fa6..ca2aff015 100644 --- a/packages/webpack-config/src/config/css.ts +++ b/packages/webpack-config/src/config/css.ts @@ -10,13 +10,12 @@ import type { ModifyWebpackConfig } from '../types.js'; type CSSRuleConfig = [string, string?, Record<string, any>?]; interface Options { publicPath: string; - browsers: string[]; } const require = createRequire(import.meta.url); function configCSSRule(config: CSSRuleConfig, options: Options) { - const { publicPath, browsers } = options; + const { publicPath } = options; const [style, loader, loaderOptions] = config; const cssLoaderOpts = { sourceMap: true, @@ -57,7 +56,6 @@ function configCSSRule(config: CSSRuleConfig, options: Options) { features: { 'custom-properties': false, }, - browsers, }], ['@ice/bundles/compiled/postcss-plugin-rpx2vw'], ], @@ -94,7 +92,7 @@ function configCSSRule(config: CSSRuleConfig, options: Options) { } const css: ModifyWebpackConfig<Configuration, typeof webpack> = (config, ctx) => { - const { supportedBrowsers, publicPath, hashKey, cssFilename, cssChunkFilename } = ctx; + const { publicPath, hashKey, cssFilename, cssChunkFilename } = ctx; const cssOutputFolder = 'css'; config.module.rules.push(...([ ['css'], @@ -105,7 +103,7 @@ const css: ModifyWebpackConfig<Configuration, typeof webpack> = (config, ctx) => ['scss', require.resolve('@ice/bundles/compiled/sass-loader'), { implementation: sass, }], - ] as CSSRuleConfig[]).map((config) => configCSSRule(config, { publicPath, browsers: supportedBrowsers }))); + ] as CSSRuleConfig[]).map((config) => configCSSRule(config, { publicPath }))); config.plugins.push( new MiniCssExtractPlugin({ filename: cssFilename || `${cssOutputFolder}/${hashKey ? `[name]-[${hashKey}].css` : '[name].css'}`, diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index 347cf1a2f..fd9772b7b 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -13,7 +13,6 @@ import ESlintPlugin from '@ice/bundles/compiled/eslint-webpack-plugin/index.js'; import CopyPlugin from '@ice/bundles/compiled/copy-webpack-plugin/index.js'; import type { NormalModule, Compiler, Configuration } from 'webpack'; import type webpack from 'webpack'; -import browserslist from 'browserslist'; import type { Config, ModifyWebpackConfig } from './types.js'; import configAssets from './config/assets.js'; import configCss from './config/css.js'; @@ -100,7 +99,6 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT } = config; const absoluteOutputDir = path.isAbsolute(outputDir) ? outputDir : path.join(rootDir, outputDir); const dev = mode !== 'production'; - const supportedBrowsers = getSupportedBrowsers(rootDir, dev); const hashKey = hash === true ? 'hash:8' : (hash || ''); // formate alias const aliasWithRoot = {}; @@ -401,7 +399,6 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT // pipe webpack by built-in functions and custom functions const ctx = { ...config, - supportedBrowsers, hashKey, webpack, }; @@ -421,23 +418,6 @@ function getDevtoolValue(sourceMap: Config['sourceMap']) { return 'source-map'; } -function getSupportedBrowsers( - dir: string, - isDevelopment: boolean, -): string[] | undefined { - let browsers: any; - try { - browsers = browserslist.loadConfig({ - path: dir, - env: isDevelopment ? 'development' : 'production', - }); - } catch { - consola.debug('[browsers]', 'fail to load config of browsers'); - } - - return browsers; -} - export { getWebpackConfig, getCompilerPlugins, diff --git a/packages/webpack-config/src/types.ts b/packages/webpack-config/src/types.ts index 9621387c2..6a96bc788 100644 --- a/packages/webpack-config/src/types.ts +++ b/packages/webpack-config/src/types.ts @@ -28,7 +28,6 @@ interface PredefinedOptions { export type MinimizerOptions<T> = PredefinedOptions & InferDefaultType<T>; interface ConfigurationCtx<T = typeof webpack> extends Config { - supportedBrowsers: string[]; hashKey: string; webpack: T; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 32d8e7a97..4d6cb9ff9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1146,7 +1146,6 @@ importers: '@ice/swc-plugin-remove-export': 0.1.1 '@rollup/pluginutils': ^4.2.0 '@swc/core': 1.3.3 - browserslist: ^4.19.3 consola: ^2.15.3 esbuild: ^0.14.51 fast-glob: ^3.2.11 @@ -1159,7 +1158,6 @@ importers: '@ice/swc-plugin-remove-export': 0.1.1 '@rollup/pluginutils': 4.2.1 '@swc/core': 1.3.3 - browserslist: 4.21.4 consola: 2.15.3 fast-glob: 3.2.12 devDependencies: From 7c07270e9843dab3f421bb94168f8e34643729ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=B0=B4=E6=BE=9C?= <shuilan.cj@taobao.com> Date: Mon, 7 Nov 2022 10:39:12 +0800 Subject: [PATCH 14/22] fix: request in data loader (#662) * fix: support request in data loader * fix: type * fix: type * fix: ts error * fix: type * feat: support config exports in plugin * fix: filter static modules * refactor: rename --- examples/with-plugin-request/ice.config.mts | 1 - packages/ice/src/plugins/web/index.ts | 4 +-- packages/ice/src/types/plugin.ts | 1 + packages/ice/src/webpack/DataLoaderPlugin.ts | 19 ++++++++++-- .../ice/templates/exports/data-loader.ts.ejs | 27 ++++++++++++++--- packages/plugin-request/src/index.ts | 1 + packages/runtime/src/dataLoader.ts | 29 +++++++++++++++++-- packages/runtime/src/types.ts | 13 +++++++++ 8 files changed, 83 insertions(+), 12 deletions(-) diff --git a/examples/with-plugin-request/ice.config.mts b/examples/with-plugin-request/ice.config.mts index 5685132f3..b0076d018 100644 --- a/examples/with-plugin-request/ice.config.mts +++ b/examples/with-plugin-request/ice.config.mts @@ -2,7 +2,6 @@ import { defineConfig } from '@ice/app'; import request from '@ice/plugin-request'; export default defineConfig({ - dataLoader: false, plugins: [ request(), ], diff --git a/packages/ice/src/plugins/web/index.ts b/packages/ice/src/plugins/web/index.ts index c99971361..c099366d3 100644 --- a/packages/ice/src/plugins/web/index.ts +++ b/packages/ice/src/plugins/web/index.ts @@ -13,7 +13,7 @@ import getServerCompilerPlugin from '../../utils/getServerCompilerPlugin.js'; const plugin: Plugin = () => ({ name: 'plugin-web', - setup: ({ registerTask, onHook, context, generator, serverCompileTask, dataCache }) => { + setup: ({ registerTask, onHook, context, generator, serverCompileTask, dataCache, getAllPlugin }) => { const { rootDir, commandArgs, command, userConfig } = context; const { ssg } = userConfig; @@ -52,7 +52,7 @@ const plugin: Plugin = () => ({ serverOutfile = path.join(outputDir, SERVER_OUTPUT_DIR, `index${userConfig?.server?.format === 'esm' ? '.mjs' : '.cjs'}`); webpackConfigs[0].plugins.push( // Add webpack plugin of data-loader in web task - new DataLoaderPlugin({ serverCompiler, rootDir, dataCache }), + new DataLoaderPlugin({ serverCompiler, rootDir, dataCache, getAllPlugin }), // Add ServerCompilerPlugin getServerCompilerPlugin(serverCompiler, { rootDir, diff --git a/packages/ice/src/types/plugin.ts b/packages/ice/src/types/plugin.ts index 2b92e0b1f..10162a6a6 100644 --- a/packages/ice/src/types/plugin.ts +++ b/packages/ice/src/types/plugin.ts @@ -131,6 +131,7 @@ export interface OverwritePluginAPI extends ExtendsPluginAPI { export interface PluginData extends _Plugin<Config, OverwritePluginAPI> { runtime?: string; staticRuntime?: boolean; + keepExports?: string[]; } export type Plugin<Options = any> = (options?: Options) => PluginData; diff --git a/packages/ice/src/webpack/DataLoaderPlugin.ts b/packages/ice/src/webpack/DataLoaderPlugin.ts index 2ade8ea3d..d83bc52ed 100644 --- a/packages/ice/src/webpack/DataLoaderPlugin.ts +++ b/packages/ice/src/webpack/DataLoaderPlugin.ts @@ -3,7 +3,8 @@ import fse from 'fs-extra'; import consola from 'consola'; import type { Compiler } from 'webpack'; import webpack from '@ice/bundles/compiled/webpack/index.js'; -import type { ServerCompiler } from '../types/plugin.js'; +import type { Context } from 'build-scripts'; +import type { ServerCompiler, PluginData } from '../types/plugin.js'; import { RUNTIME_TMP_DIR } from '../constant.js'; import { getRoutePathsFromCache } from '../utils/getRoutePaths.js'; @@ -14,19 +15,31 @@ export default class DataLoaderPlugin { private serverCompiler: ServerCompiler; private rootDir: string; private dataCache: Map<string, string>; + private getAllPlugin: Context['getAllPlugin']; public constructor(options: { serverCompiler: ServerCompiler; rootDir: string; dataCache: Map<string, string>; + getAllPlugin?: Context['getAllPlugin']; }) { - const { serverCompiler, rootDir, dataCache } = options; + const { serverCompiler, rootDir, dataCache, getAllPlugin } = options; this.serverCompiler = serverCompiler; this.rootDir = rootDir; this.dataCache = dataCache; + this.getAllPlugin = getAllPlugin; } public apply(compiler: Compiler) { + const plugins = this.getAllPlugin(['keepExports']) as PluginData[]; + + let keepExports = ['getData', 'getAppData']; + plugins.forEach(plugin => { + if (plugin.keepExports) { + keepExports = keepExports.concat(plugin.keepExports); + } + }); + compiler.hooks.thisCompilation.tap(pluginName, (compilation) => { compilation.hooks.processAssets.tapAsync({ name: pluginName, @@ -45,7 +58,7 @@ export default class DataLoaderPlugin { }, { swc: { - keepExports: ['getData', 'getAppData'], + keepExports, keepPlatform: 'web', getRoutePaths: () => { return getRoutePathsFromCache(this.dataCache); diff --git a/packages/ice/templates/exports/data-loader.ts.ejs b/packages/ice/templates/exports/data-loader.ts.ejs index e3554b974..d891d3cc9 100644 --- a/packages/ice/templates/exports/data-loader.ts.ejs +++ b/packages/ice/templates/exports/data-loader.ts.ejs @@ -1,7 +1,15 @@ import { dataLoader } from '@ice/runtime'; -<% if(hasExportAppData) {-%>import { getAppData } from '@/app';<% } -%> - +<% if(hasExportAppData) {-%>import * as app from '@/app';<% } -%> <% if(dataLoaderImport.imports) {-%><%-dataLoaderImport.imports%><% } -%> +<% const staticModuleNames = []; -%> +<% if (runtimeModules.length) { -%> + <% runtimeModules.forEach((runtimeModule, index) => { -%> + <% if (runtimeModule.staticRuntime) { -%> + import module<%= index %> from '<%= runtimeModule.path %>'; + <% staticModuleNames.push('module' + index) -%> + <% } -%> + <% }) -%> +<% } -%> <% if (loaders) {-%> <%- loaders %> @@ -9,7 +17,7 @@ import { dataLoader } from '@ice/runtime'; const loaders = {}; <% } -%> -<% if(hasExportAppData) {-%>loaders['__app'] = getAppData;<% } -%> +<% if(hasExportAppData) {-%>loaders['__app'] = app.getAppData;<% } -%> <% if(!dataLoaderImport.imports) {-%> let fetcher = (options) => { @@ -17,4 +25,15 @@ let fetcher = (options) => { } <% } -%> -dataLoader.init(loaders, fetcher); +// Only init static runtime in data-loader. +const staticRuntimeModules = [ +<% staticModuleNames.forEach((moduleName, index) => { -%> + <%= moduleName %>, +<% }) -%> +]; + +dataLoader.init(loaders, { + fetcher, + runtimeModules: staticRuntimeModules, + appExport: app, +}); diff --git a/packages/plugin-request/src/index.ts b/packages/plugin-request/src/index.ts index a5e9aa1b4..6ac5163e6 100644 --- a/packages/plugin-request/src/index.ts +++ b/packages/plugin-request/src/index.ts @@ -26,6 +26,7 @@ const plugin: Plugin<PluginRequestOptions | void> = () => ({ }, runtime: `${PLUGIN_NAME}/esm/runtime`, staticRuntime: true, + keepExports: ['request'], }); export type { diff --git a/packages/runtime/src/dataLoader.ts b/packages/runtime/src/dataLoader.ts index 8b2914f18..b7e9bd8ce 100644 --- a/packages/runtime/src/dataLoader.ts +++ b/packages/runtime/src/dataLoader.ts @@ -1,4 +1,4 @@ -import type { GetData, GetDataConfig } from './types.js'; +import type { GetData, GetDataConfig, RuntimeModules, AppExport, RuntimePlugin, CommonJsRuntime } from './types.js'; import getRequestContext from './requestContext.js'; interface Loaders { @@ -110,11 +110,36 @@ function getLoaders(loadersConfig: LoadersConfig, fetcher: Function): Loaders { return loaders; } +interface Options { + fetcher: Function; + runtimeModules: RuntimeModules['statics']; + appExport: AppExport; +} + /** * Load initial data and register global loader. * In order to load data, JavaScript modules, CSS and other assets in parallel. */ -function init(loadersConfig: LoadersConfig, fetcher: Function) { +async function init(loadersConfig: LoadersConfig, options: Options) { + const { + fetcher, + runtimeModules, + appExport, + } = options; + + const runtimeApi = { + appContext: { + appExport, + }, + }; + + if (runtimeModules) { + await Promise.all(runtimeModules.map(module => { + const runtimeModule = (module as CommonJsRuntime).default || module as RuntimePlugin; + return runtimeModule(runtimeApi); + }).filter(Boolean)); + } + const loaders = getLoaders(loadersConfig, fetcher); try { diff --git a/packages/runtime/src/types.ts b/packages/runtime/src/types.ts index c7145d4c1..3dad4633c 100644 --- a/packages/runtime/src/types.ts +++ b/packages/runtime/src/types.ts @@ -171,6 +171,12 @@ export interface RuntimeAPI { useAppContext: UseAppContext; } +export interface StaticRuntimeAPI { + appContext: { + appExport: AppExport; + }; +} + export interface RuntimePlugin { ( apis: RuntimeAPI, @@ -178,6 +184,13 @@ export interface RuntimePlugin { ): Promise<void> | void; } +export interface RuntimePlugin { + ( + apis: StaticRuntimeAPI, + runtimeOptions?: Record<string, any>, + ): Promise<void> | void; +} + export interface CommonJsRuntime { default: RuntimePlugin; } From 504b5afcdc9a135eb5ae33dbd41ca26861fbb5e2 Mon Sep 17 00:00:00 2001 From: luhc228 <44047106+luhc228@users.noreply.github.com> Date: Mon, 7 Nov 2022 10:57:48 +0800 Subject: [PATCH 15/22] feat: support weex platform (#616) * chore: remove platform options * chore: add weex platform --- packages/ice/bin/ice-cli.mjs | 6 ++---- packages/ice/src/constant.ts | 2 ++ 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/ice/bin/ice-cli.mjs b/packages/ice/bin/ice-cli.mjs index 0323b3c62..249f36f36 100755 --- a/packages/ice/bin/ice-cli.mjs +++ b/packages/ice/bin/ice-cli.mjs @@ -7,8 +7,8 @@ import detectPort from 'detect-port'; // hijack webpack before import other modules import '../esm/requireHook.js'; import createService from '../esm/createService.js'; -import checkNodeVersion from './checkNodeVersion.mjs'; import { ALL_PLATFORMS } from '../esm/constant.js'; +import checkNodeVersion from './checkNodeVersion.mjs'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); @@ -18,9 +18,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); process.env.__ICE_VERSION__ = icePackageInfo.version; const cwd = process.cwd(); - program - .version(icePackageInfo.version) - .usage('<command> [options]'); + program.version(icePackageInfo.version).usage('<command> [options]'); program .command('build') diff --git a/packages/ice/src/constant.ts b/packages/ice/src/constant.ts index 0c2c9c3dc..3d1521378 100644 --- a/packages/ice/src/constant.ts +++ b/packages/ice/src/constant.ts @@ -17,6 +17,7 @@ export const BUILDIN_CJS_DEPS = [ ]; export const WEB = 'web'; +export const WEEX = 'weex'; export const ALI_MINIAPP = 'ali-miniapp'; export const WECHAT_MINIPROGRAM = 'wechat-miniprogram'; export const BYTEDANCE_MICROAPP = 'bytedance-microapp'; @@ -29,5 +30,6 @@ export const MINIAPP_PLATFORMS = [ ]; export const ALL_PLATFORMS = [ WEB, + WEEX, ...MINIAPP_PLATFORMS, ]; From ec8553ad4cf21b11bb8dbc47e75eaf47ebc61fbd Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Mon, 7 Nov 2022 11:15:50 +0800 Subject: [PATCH 16/22] fix: re-compile server bundle after document changed (#663) * fix: re-compile server bundle after document changed * fix: optimize code --- packages/ice/src/plugins/web/index.ts | 40 ++++++++++++++----- .../ice/src/webpack/ServerCompilerPlugin.ts | 35 +++++++++++----- 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/packages/ice/src/plugins/web/index.ts b/packages/ice/src/plugins/web/index.ts index c099366d3..a4fa6f206 100644 --- a/packages/ice/src/plugins/web/index.ts +++ b/packages/ice/src/plugins/web/index.ts @@ -1,6 +1,7 @@ import * as path from 'path'; import consola from 'consola'; import chalk from 'chalk'; +import lodash from '@ice/bundles/compiled/lodash/index.js'; import type { Plugin } from '../../types/plugin.js'; import ReCompilePlugin from '../../webpack/ReCompilePlugin.js'; import DataLoaderPlugin from '../../webpack/DataLoaderPlugin.js'; @@ -10,10 +11,13 @@ import getWebTask from '../../tasks/web/index.js'; import generateHTML from '../../utils/generateHTML.js'; import openBrowser from '../../utils/openBrowser.js'; import getServerCompilerPlugin from '../../utils/getServerCompilerPlugin.js'; +import type ServerCompilerPlugin from '../../webpack/ServerCompilerPlugin.js'; + +const { debounce } = lodash; const plugin: Plugin = () => ({ name: 'plugin-web', - setup: ({ registerTask, onHook, context, generator, serverCompileTask, dataCache, getAllPlugin }) => { + setup: ({ registerTask, onHook, context, generator, serverCompileTask, dataCache, watch, getAllPlugin }) => { const { rootDir, commandArgs, command, userConfig } = context; const { ssg } = userConfig; @@ -45,24 +49,26 @@ const plugin: Plugin = () => ({ }); let serverOutfile: string; + let serverCompilerPlugin: ServerCompilerPlugin; onHook(`before.${command as 'start' | 'build'}.run`, async ({ webpackConfigs, taskConfigs, serverCompiler }) => { // Compile server entry after the webpack compilation. const { reCompile: reCompileRouteConfig, ensureRoutesConfig } = getRouteExportConfig(rootDir); const outputDir = webpackConfigs[0].output.path; serverOutfile = path.join(outputDir, SERVER_OUTPUT_DIR, `index${userConfig?.server?.format === 'esm' ? '.mjs' : '.cjs'}`); + serverCompilerPlugin = getServerCompilerPlugin(serverCompiler, { + rootDir, + serverEntry: taskConfigs[0].config?.server?.entry, + outputDir: webpackConfigs[0].output.path, + dataCache, + serverCompileTask: command === 'start' ? serverCompileTask : null, + userConfig, + ensureRoutesConfig, + }); webpackConfigs[0].plugins.push( // Add webpack plugin of data-loader in web task new DataLoaderPlugin({ serverCompiler, rootDir, dataCache, getAllPlugin }), // Add ServerCompilerPlugin - getServerCompilerPlugin(serverCompiler, { - rootDir, - serverEntry: taskConfigs[0].config?.server?.entry, - outputDir: webpackConfigs[0].output.path, - dataCache, - serverCompileTask: command === 'start' ? serverCompileTask : null, - userConfig, - ensureRoutesConfig, - }), + serverCompilerPlugin, ); if (command === 'start') { @@ -77,6 +83,20 @@ const plugin: Plugin = () => ({ return files.some((filePath) => routeFiles.some(routeFile => filePath.includes(routeFile))); }), ); + const debounceCompile = debounce(() => { + console.log('Document updated, try to reload page for latest html content.'); + if (serverCompilerPlugin) { + serverCompilerPlugin.compileTask(); + } + }, 200); + watch.addEvent([ + /src\/document(\/index)?(.js|.jsx|.tsx)/, + (event: string) => { + if (event === 'change') { + debounceCompile(); + } + }, + ]); } }); diff --git a/packages/ice/src/webpack/ServerCompilerPlugin.ts b/packages/ice/src/webpack/ServerCompilerPlugin.ts index 0ce7a04c8..2af364af9 100644 --- a/packages/ice/src/webpack/ServerCompilerPlugin.ts +++ b/packages/ice/src/webpack/ServerCompilerPlugin.ts @@ -11,6 +11,8 @@ export default class ServerCompilerPlugin { private serverCompilerOptions: Parameters<ServerCompiler>; private serverCompileTask: ExtendsPluginAPI['serverCompileTask']; private ensureRoutesConfig: () => Promise<void>; + private isCompiling: boolean; + private lastAssets: string; public constructor( serverCompiler: ServerCompiler, @@ -24,17 +26,32 @@ export default class ServerCompilerPlugin { this.ensureRoutesConfig = ensureRoutesConfig; } + public compileTask = async (compilation?: Compilation) => { + const [buildOptions, customConfig = {}] = this.serverCompilerOptions; + let task = null; + if (!this.isCompiling) { + await this.ensureRoutesConfig(); + let assets = this.lastAssets; + if (compilation) { + assets = compilation.assets['assets-manifest.json'].source().toString(); + // Store last assets for compilation Document. + this.lastAssets = assets; + } + task = this.serverCompiler(buildOptions, { + ...customConfig, + assetsManifest: JSON.parse(assets), + }); + } + return task; + }; + public apply(compiler: Compiler) { + compiler.hooks.watchRun.tap(pluginName, () => { + this.isCompiling = true; + }); compiler.hooks.emit.tapPromise(pluginName, async (compilation: Compilation) => { - const [buildOptions, customConfig = {}] = this.serverCompilerOptions; - - await this.ensureRoutesConfig(); - - const task = this.serverCompiler(buildOptions, { - ...customConfig, - assetsManifest: JSON.parse(compilation.assets['assets-manifest.json'].source().toString()), - }); - + this.isCompiling = false; + const task = await this.compileTask(compilation); if (this.serverCompileTask) { this.serverCompileTask.set(task); } else { From 1aaf6b7725dbb8975fec1fe17d908a54711021bf Mon Sep 17 00:00:00 2001 From: NK <xianyong.yxy@alibaba-inc.com> Date: Mon, 7 Nov 2022 11:19:17 +0800 Subject: [PATCH 17/22] feat(miniapp): add miniapp html styles package (#555) --- examples/miniapp-project/package.json | 1 + examples/miniapp-project/src/global.less | 2 + packages/miniapp-html-styles/README.md | 14 + packages/miniapp-html-styles/html.css | 262 +++++++++ packages/miniapp-html-styles/html5.css | 649 ++++++++++++++++++++++ packages/miniapp-html-styles/package.json | 19 + pnpm-lock.yaml | 5 + 7 files changed, 952 insertions(+) create mode 100644 packages/miniapp-html-styles/README.md create mode 100644 packages/miniapp-html-styles/html.css create mode 100644 packages/miniapp-html-styles/html5.css create mode 100644 packages/miniapp-html-styles/package.json diff --git a/examples/miniapp-project/package.json b/examples/miniapp-project/package.json index 1d65529c9..94c3253cc 100644 --- a/examples/miniapp-project/package.json +++ b/examples/miniapp-project/package.json @@ -14,6 +14,7 @@ "dependencies": { "@ice/app": "workspace:*", "@ice/runtime": "workspace:*", + "@ice/miniapp-html-styles": "workspace:*", "@ice/plugin-miniapp": "workspace:*", "@ice/miniapp-runtime": "workspace:*", "ahooks": "^3.3.8", diff --git a/examples/miniapp-project/src/global.less b/examples/miniapp-project/src/global.less index 8438e6e95..72966bc91 100644 --- a/examples/miniapp-project/src/global.less +++ b/examples/miniapp-project/src/global.less @@ -1,3 +1,5 @@ +@import '@ice/miniapp-html-styles/html'; + .global { font-size: 14px; } diff --git a/packages/miniapp-html-styles/README.md b/packages/miniapp-html-styles/README.md new file mode 100644 index 000000000..7ef3c9dfb --- /dev/null +++ b/packages/miniapp-html-styles/README.md @@ -0,0 +1,14 @@ +# @ice/miniapp-html-styles + +> Forked from [@tarojs/taro](https://github.com/NervJS/taro/tree/next/packages/taro) with respect ❤️ +> Licensed under the MIT License +> https://github.com/NervJS/taro/blob/next/LICENSE + +## html.css + +W3C HTML4 的内置样式,用于兼容 HTML 标签样式 + +## html5.css + +Chrome(Blink) HTML5 的内置样式,用于兼容 HTML 标签样式 + diff --git a/packages/miniapp-html-styles/html.css b/packages/miniapp-html-styles/html.css new file mode 100644 index 000000000..06327d050 --- /dev/null +++ b/packages/miniapp-html-styles/html.css @@ -0,0 +1,262 @@ +/* + Default Styles for HTML4 (W3C spec): + https://www.w3.org/TR/CSS2/sample.html +*/ + +.h5-html, +.h5-address, +.h5-blockquote, +.h5-body, +.h5-dd, +.h5-div, +.h5-dl, +.h5-dt, +.h5-fieldset, +.h5-form, +.h5-frame, +.h5-frameset, +.h5-h1, +.h5-h2, +.h5-h3, +.h5-h4, +.h5-h5, +.h5-h6, +.h5-noframes, +.h5-ol, +.h5-p, +.h5-ul, +.h5-center, +.h5-dir, +.h5-hr, +.h5-menu, +.h5-pre { + display: block; + unicode-bidi: embed; +} + +.h5-li { + display: list-item; +} + +.h5-head { + display: none; +} + +.h5-table { + display: table; + border-spacing: 2px; +} + +.h5-tr { + display: table-row; +} + +.h5-thead { + display: table-header-group; +} + +.h5-tbody { + display: table-row-group; +} + +.h5-tfoot { + display: table-footer-group; +} + +.h5-col { + display: table-column; +} + +.h5-colgroup { + display: table-column-group; +} + +.h5-td, +.h5-th { + display: table-cell; +} + +.h5-caption { + display: table-caption; + text-align: center; +} + +.h5-th { + text-align: center; + font-weight: bolder; +} + +.h5-body { + margin: 8px; +} + +.h5-h1 { + margin: 0.67em 0; + font-size: 2em; +} + +.h5-h2 { + margin: 0.75em 0; + font-size: 1.5em; +} + +.h5-h3 { + margin: 0.83em 0; + font-size: 1.17em; +} + +.h5-h4, +.h5-p, +.h5-blockquote, +.h5-ul, +.h5-fieldset, +.h5-form, +.h5-ol, +.h5-dl, +.h5-dir, +.h5-menu { + margin: 1.12em 0; +} + +.h5-h5 { + margin: 1.5em 0; + font-size: 0.83em; +} + +.h5-h6 { + margin: 1.67em 0; + font-size: 0.75em; +} + +.h5-h1, +.h5-h2, +.h5-h3, +.h5-h4, +.h5-h5, +.h5-h6, +.h5-b, +.h5-strong { + font-weight: bolder; +} + +.h5-blockquote { + margin-left: 40px; + margin-right: 40px; +} + +.h5-i, +.h5-cite, +.h5-em, +.h5-var, +.h5-address { + font-style: italic; +} + +.h5-pre, +.h5-tt, +.h5-code, +.h5-kbd, +.h5-samp { + font-family: monospace; +} + +.h5-pre { + white-space: pre; +} + +.h5-button, +.h5-textarea, +.h5-input, +.h5-select { + display: inline-block; +} + +.h5-big { + font-size: 1.17em; +} + +.h5-small, +.h5-sub, +.h5-sup { + font-size: 0.83em; +} + +.h5-sub { + vertical-align: sub; +} + +.h5-sup { + vertical-align: super; +} + +.h5-thead, +.h5-tbody, +.h5-tfoot { + vertical-align: middle; +} + +.h5-td, +.h5-th, +.h5-tr { + vertical-align: inherit; +} + +.h5-s, +.h5-strike, +.h5-del { + text-decoration: line-through; +} + +.h5-hr { + border: 1px inset; +} + +.h5-ol, +.h5-ul, +.h5-dir, +.h5-menu, +.h5-dd { + margin-left: 40px; +} + +.h5-ol { + list-style-type: decimal; +} + +.h5-ol .h5-ul, +.h5-ul .h5-ol, +.h5-ul .h5-ul, +.h5-ol .h5-ol { + margin-top: 0; + margin-bottom: 0; +} + +.h5-u, +.h5-ins { + text-decoration: underline; +} + +.h5-br::before { + white-space: pre-line; + content: "\A"; +} + +.h5-center { + text-align: center; +} + +input[type="hidden"] { + display: none !important; +} + +.h5-a { + display: inline; +} + +.h5-button::after { + border: none; +} + +.h5-span { + display: inline; +} diff --git a/packages/miniapp-html-styles/html5.css b/packages/miniapp-html-styles/html5.css new file mode 100644 index 000000000..11b626756 --- /dev/null +++ b/packages/miniapp-html-styles/html5.css @@ -0,0 +1,649 @@ +.h5-html { + display: block; +} + +.h5-head { + display: none; +} + +.h5-meta { + display: none; +} + +.h5-title { + display: none; +} + +.h5-link { + display: none; +} + +.h5-style { + display: none; +} + +.h5-script { + display: none; +} + +.h5-body { + display: block; + margin: 8px; +} + +.h5-p { + display: block; + margin-block-start: 1em; + margin-block-end: 1em; + margin-inline-start: 0; + margin-inline-end: 0; +} + +.h5-div { + display: block; +} + +.h5-layer { + display: block; +} + +.h5-article, +.h5-aside, +.h5-footer, +.h5-header, +.h5-hgroup, +.h5-main, +.h5-nav, +.h5-section { + display: block; +} + +.h5-marquee { + display: inline-block; + width: stretch; +} + +.h5-address { + display: block; +} + +.h5-blockquote { + display: block; + margin-block-start: 1em; + margin-block-end: 1em; + margin-inline-start: 40px; + margin-inline-end: 40px; +} + +.h5-figcaption { + display: block; +} + +.h5-figure { + display: block; + margin-block-start: 1em; + margin-block-end: 1em; + margin-inline-start: 40px; + margin-inline-end: 40px; +} + +.h5-q { + display: inline; +} + +.h5-q::before { + content: open-quote; +} + +.h5-q::after { + content: close-quote; +} + +.h5-center { + display: block; + text-align: -webkit-center; +} + +.h5-hr { + display: block; + overflow: hidden; + border-width: 1px; + border-style: inset; + unicode-bidi: isolate; + margin-block-start: 0.5em; + margin-block-end: 0.5em; + margin-inline-start: auto; + margin-inline-end: auto; +} + +.h5-map { + display: inline; +} + +.h5-video { + object-fit: contain; +} + +.h5-h1 { + display: block; + font-weight: bold; + font-size: 2em; + margin-block-start: 0.67em; + margin-block-end: 0.67em; + margin-inline-start: 0; + margin-inline-end: 0; +} + +:-webkit-any(.h5-article) .h5-h1 { + font-size: 1.5em; + margin-block-start: 0.83em; + margin-block-end: 0.83em; +} + +:-webkit-any(.h5-article) :-webkit-any(.h5-article) .h5-h1 { + font-size: 1.17em; + margin-block-start: 1em; + margin-block-end: 1em; +} + +:-webkit-any(.h5-article) :-webkit-any(.h5-article) :-webkit-any(.h5-article) .h5-h1 { + font-size: 1em; + margin-block-start: 1.33em; + margin-block-end: 1.33em; +} + +:-webkit-any(.h5-article) :-webkit-any(.h5-article) :-webkit-any(.h5-article) :-webkit-any(.h5-article) .h5-h1 { + font-size: 0.83em; + margin-block-start: 1.67em; + margin-block-end: 1.67em; +} + +:-webkit-any(.h5-article) :-webkit-any(.h5-article) :-webkit-any(.h5-article) :-webkit-any(.h5-article) :-webkit-any(.h5-article) .h5-h1 { + font-size: 0.67em; + margin-block-start: 2.33em; + margin-block-end: 2.33em; +} + +.h5-h2 { + display: block; + font-weight: bold; + font-size: 1.5em; + margin-block-start: 0.83em; + margin-block-end: 0.83em; + margin-inline-start: 0; + margin-inline-end: 0; +} + +.h5-h3 { + display: block; + font-weight: bold; + font-size: 1.17em; + margin-block-start: 1em; + margin-block-end: 1em; + margin-inline-start: 0; + margin-inline-end: 0; +} + +.h5-h4 { + display: block; + margin-block-start: 1.33em; + margin-block-end: 1.33em; + margin-inline-start: 0; + margin-inline-end: 0; + font-weight: bold; +} + +.h5-h5 { + display: block; + font-weight: bold; + font-size: 0.83em; + margin-block-start: 1.67em; + margin-block-end: 1.67em; + margin-inline-start: 0; + margin-inline-end: 0; +} + +.h5-h6 { + display: block; + font-weight: bold; + font-size: 0.67em; + margin-block-start: 2.33em; + margin-block-end: 2.33em; + margin-inline-start: 0; + margin-inline-end: 0; +} + +.h5-table { + display: table; + border-collapse: separate; + border-spacing: 2px; + box-sizing: border-box; + border-color: gray; + text-indent: initial; +} + +.h5-thead { + display: table-header-group; + border-color: inherit; + vertical-align: middle; +} + +.h5-tbody { + display: table-row-group; + border-color: inherit; + vertical-align: middle; +} + +.h5-tfoot { + display: table-footer-group; + border-color: inherit; + vertical-align: middle; +} + +.h5-table > .h5-tr { + vertical-align: middle; +} + +.h5-col { + display: table-column; +} + +.h5-colgroup { + display: table-column-group; +} + +.h5-tr { + display: table-row; + border-color: inherit; + vertical-align: inherit; +} + +.h5-td, +.h5-th { + display: table-cell; + vertical-align: inherit; +} + +.h5-th { + text-align: -internal-center; + font-weight: bold; +} + +.h5-caption { + display: table-caption; + text-align: -webkit-center; +} + +.h5-ul, +.h5-menu, +.h5-dir { + display: block; + list-style-type: disc; + margin-block-start: 1em; + margin-block-end: 1em; + margin-inline-start: 0; + margin-inline-end: 0; + padding-inline-start: 40px; +} + +.h5-ol { + display: block; + list-style-type: decimal; + margin-block-start: 1em; + margin-block-end: 1em; + margin-inline-start: 0; + margin-inline-end: 0; + padding-inline-start: 40px; +} + +.h5-li { + display: list-item; + text-align: -webkit-match-parent; +} + +.h5-ul .h5-ul, +.h5-ol .h5-ul { + list-style-type: circle; +} + +.h5-ol .h5-ol .h5-ul, +.h5-ol .h5-ul .h5-ul, +.h5-ul .h5-ol .h5-ul, +.h5-ul .h5-ul .h5-ul { + list-style-type: square; +} + +.h5-dd { + display: block; + margin-inline-start: 40px; +} + +.h5-dl { + display: block; + margin-block-start: 1em; + margin-block-end: 1em; + margin-inline-start: 0; + margin-inline-end: 0; +} + +.h5-dt { + display: block; +} + +.h5-ol .h5-ul, +.h5-ul .h5-ol, +.h5-ul .h5-ul, +.h5-ol .h5-ol { + margin-block-start: 0; + margin-block-end: 0; +} + +.h5-form { + display: block; + margin-top: 0; +} + +.h5-label { + cursor: default; +} + +.h5-legend { + display: block; + padding-inline-start: 2px; + padding-inline-end: 2px; + border: none; +} + +.h5-fieldset { + display: block; + margin-inline-start: 2px; + margin-inline-end: 2px; + padding-block-start: 0.35em; + padding-inline-start: 0.75em; + padding-inline-end: 0.75em; + padding-block-end: 0.625em; + border: 2px groove ThreeDFace; + min-inline-size: min-content; +} + +.h5-button { + appearance: auto; +} + +.h5-input, +.h5-textarea, +.h5-select, +.h5-button, +.h5-meter, +.h5-progress { + writing-mode: horizontal-tb !important; +} + +.h5-input, +.h5-textarea, +.h5-select, +.h5-button { + display: inline-block; + margin: 0; + line-height: normal; + text-align: start; + text-indent: 0; + text-shadow: none; + text-transform: none; + font-variant: small-control; + color: black; + word-spacing: normal; + letter-spacing: normal; + text-rendering: auto; +} + +.h5-textarea { + column-count: initial !important; + padding: 2px; + border: 1px solid #767676; + appearance: auto; + background-color: #fff; + resize: auto; + cursor: text; + font-family: monospace; + word-wrap: break-word; + white-space: pre-wrap; + -webkit-rtl-ordering: logical; +} + +.h5-input { + padding: 1px 0; + border: 2px inset #767676; + appearance: auto; + background-color: #fff; + cursor: text; + -webkit-rtl-ordering: logical; +} + +.h5-option:-internal-spatial-navigation-focus { + outline: black dashed 1px; + outline-offset: -1px; +} + +.h5-datalist { + display: none; +} + +.h5-area { + display: inline; +} + +.h5-param { + display: none; +} + +.h5-select { + align-items: center; + box-sizing: border-box; + border: 1px solid #767676; + border-radius: 0; + appearance: auto; + background-color: #fff; + cursor: default; + color: black; + white-space: pre; + -webkit-rtl-ordering: logical; +} + +.h5-optgroup { + display: block; + font-weight: bolder; +} + +.h5-option { + display: block; + padding: 0 2px 1px; + min-height: 1.2em; + font-weight: normal; + white-space: nowrap; +} + +.h5-selectmenu { + display: inline-block; +} + +.h5-output { + display: inline; +} + +.h5-meter { + display: inline-block; + box-sizing: border-box; + width: 5em; + height: 1em; + appearance: auto; + -webkit-user-modify: read-only !important; + vertical-align: -0.2em; +} + +.h5-progress { + display: inline-block; + box-sizing: border-box; + width: 10em; + height: 1em; + appearance: auto; + vertical-align: -0.2em; +} + +.h5-u, +.h5-ins { + text-decoration: underline; +} + +.h5-strong, +.h5-b { + font-weight: bold; +} + +.h5-i, +.h5-cite, +.h5-em, +.h5-var, +.h5-address, +.h5-dfn { + font-style: italic; +} + +.h5-tt, +.h5-code, +.h5-kbd, +.h5-samp { + font-family: monospace; +} + +.h5-pre, +.h5-xmp, +.h5-plaintext, +.h5-listing { + display: block; + margin: 1em 0; + font-family: monospace; + white-space: pre; +} + +.h5-mark { + background-color: yellow; + color: black; +} + +.h5-big { + font-size: larger; +} + +.h5-small { + font-size: smaller; +} + +.h5-s, +.h5-strike, +.h5-del { + text-decoration: line-through; +} + +.h5-sub { + vertical-align: sub; + font-size: smaller; +} + +.h5-sup { + vertical-align: super; + font-size: smaller; +} + +.h5-nobr { + white-space: nowrap; +} + +.h5-ruby, +.h5-rt { + text-indent: 0; +} + +.h5-rt { + line-height: normal; + text-emphasis: none; +} + +.h5-ruby > .h5-rt { + display: block; + text-align: start; + font-size: 50%; +} + +.h5-rp { + display: none; +} + +.h5-noframes { + display: none; +} + +.h5-frameset, +.h5-frame { + display: block; +} + +.h5-frameset { + border-color: inherit; +} + +.h5-iframe { + border: 2px inset; +} + +.h5-details { + display: block; +} + +.h5-summary { + display: block; +} + +.h5-template { + display: none; +} + +.h5-bdi, +.h5-output { + unicode-bidi: isolate; +} + +.h5-bdo { + unicode-bidi: bidi-override; +} + +.h5-dialog:not([open]) { + display: none; +} + +.h5-dialog { + display: block; + position: absolute; + left: 0; + right: 0; + margin: auto; + padding: 1em; + border: solid; + width: fit-content; + height: fit-content; + background: white; + color: black; +} + +.h5-dialog::backdrop { + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + background: rgb(0 0 0 / 10%); +} + +.h5-slot { + display: contents; +} diff --git a/packages/miniapp-html-styles/package.json b/packages/miniapp-html-styles/package.json new file mode 100644 index 000000000..19c074a39 --- /dev/null +++ b/packages/miniapp-html-styles/package.json @@ -0,0 +1,19 @@ +{ + "name": "@ice/miniapp-html-styles", + "version": "1.0.0", + "description": "html styles for ice miniapp", + "exports": { + "./html": "./html.css", + "./html5": "./html5.css" + }, + "files": [ + "html.css", + "html5.css" + ], + "author": "ICE", + "license": "MIT", + "repository": "ice-lab/ice-next", + "bugs": "https://github.com/ice-lab/ice-next/issues", + "homepage": "https://next.ice.work", + "sideEffects": false +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4d6cb9ff9..0250439b0 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -210,6 +210,7 @@ importers: examples/miniapp-project: specifiers: '@ice/app': workspace:* + '@ice/miniapp-html-styles': workspace:* '@ice/miniapp-runtime': workspace:* '@ice/plugin-miniapp': workspace:* '@ice/runtime': workspace:* @@ -223,6 +224,7 @@ importers: webpack: ^5.73.0 dependencies: '@ice/app': link:../../packages/ice + '@ice/miniapp-html-styles': link:../../packages/miniapp-html-styles '@ice/miniapp-runtime': link:../../packages/miniapp-runtime '@ice/plugin-miniapp': link:../../packages/plugin-miniapp '@ice/runtime': link:../../packages/runtime @@ -826,6 +828,9 @@ importers: react: 18.2.0 react-dom: 18.2.0_react@18.2.0 + packages/miniapp-html-styles: + specifiers: {} + packages/miniapp-loader: specifiers: '@ice/bundles': ^0.1.0 From 32bd3f0e7c9b41382c4404294e11af99c1059673 Mon Sep 17 00:00:00 2001 From: luhc228 <44047106+luhc228@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:53:18 +0800 Subject: [PATCH 18/22] fix: useAuth error (#661) * chore: example * chore: with-auth example * docs: update auth * test: add with-auth test * chore: format * fix: lock --- examples/basic-project/ice.config.mts | 2 - examples/basic-project/package.json | 1 - examples/basic-project/src/app.tsx | 13 ---- examples/basic-project/src/pages/about.tsx | 1 - examples/basic-project/src/pages/blog.tsx | 1 - examples/basic-project/src/pages/index.tsx | 2 - examples/basic-project/src/pages/layout.tsx | 1 - examples/with-auth/ice.config.mts | 8 +++ examples/with-auth/package.json | 20 +++++++ examples/with-auth/src/app.tsx | 32 ++++++++++ .../with-auth/src/components/CustomAuth.tsx | 16 +++++ examples/with-auth/src/document.tsx | 22 +++++++ examples/with-auth/src/pages/blog.tsx | 17 ++++++ examples/with-auth/src/pages/index.tsx | 24 ++++++++ examples/with-auth/tsconfig.json | 25 ++++++++ packages/plugin-auth/package.json | 5 -- packages/plugin-auth/src/index.ts | 2 +- packages/plugin-auth/src/runtime/index.tsx | 9 +-- pnpm-lock.yaml | 21 ++++++- tests/integration/with-auth.test.ts | 59 +++++++++++++++++++ website/docs/guide/advanced/auth.md | 4 +- 21 files changed, 250 insertions(+), 35 deletions(-) create mode 100644 examples/with-auth/ice.config.mts create mode 100644 examples/with-auth/package.json create mode 100644 examples/with-auth/src/app.tsx create mode 100644 examples/with-auth/src/components/CustomAuth.tsx create mode 100644 examples/with-auth/src/document.tsx create mode 100644 examples/with-auth/src/pages/blog.tsx create mode 100644 examples/with-auth/src/pages/index.tsx create mode 100644 examples/with-auth/tsconfig.json create mode 100644 tests/integration/with-auth.test.ts diff --git a/examples/basic-project/ice.config.mts b/examples/basic-project/ice.config.mts index a987e32d1..2af6cf57e 100644 --- a/examples/basic-project/ice.config.mts +++ b/examples/basic-project/ice.config.mts @@ -1,6 +1,5 @@ import { defineConfig } from '@ice/app'; import SpeedMeasurePlugin from 'speed-measure-webpack-plugin'; -import auth from '@ice/plugin-auth'; import custom from './plugin'; export default defineConfig({ @@ -23,7 +22,6 @@ export default defineConfig({ }, dropLogLevel: 'warn', plugins: [ - auth(), custom, ], eslint: true, diff --git a/examples/basic-project/package.json b/examples/basic-project/package.json index 4f79c1abc..5fe4530d1 100644 --- a/examples/basic-project/package.json +++ b/examples/basic-project/package.json @@ -11,7 +11,6 @@ "license": "MIT", "dependencies": { "@ice/app": "workspace:*", - "@ice/plugin-auth": "workspace:*", "@ice/plugin-rax-compat": "workspace:*", "@ice/runtime": "workspace:*", "@uni/env": "^1.1.0", diff --git a/examples/basic-project/src/app.tsx b/examples/basic-project/src/app.tsx index 1d848aab5..1482f3d02 100644 --- a/examples/basic-project/src/app.tsx +++ b/examples/basic-project/src/app.tsx @@ -1,5 +1,4 @@ import { defineAppConfig } from 'ice'; -import { defineAuthConfig } from '@ice/plugin-auth/esm/types'; import { isWeb, isNode } from '@uni/env'; import type { GetAppData } from 'ice'; @@ -20,15 +19,6 @@ if (isNode) { console.error('__IS_NODE__'); } -export const auth = defineAuthConfig((data) => { - // fetch auth data - return { - initialAuth: { - admin: data?.auth?.admin, - }, - }; -}); - export default defineAppConfig({ app: { rootId: 'app', @@ -39,9 +29,6 @@ export const getAppData: GetAppData = () => { return new Promise((resolve) => { resolve({ title: 'gogogogo', - auth: { - admin: true, - }, }); }); }; \ No newline at end of file diff --git a/examples/basic-project/src/pages/about.tsx b/examples/basic-project/src/pages/about.tsx index 5afe5522a..b1bce2760 100644 --- a/examples/basic-project/src/pages/about.tsx +++ b/examples/basic-project/src/pages/about.tsx @@ -41,7 +41,6 @@ export function getConfig(): RouteConfig { scripts: [{ src: 'https://cdn.jsdelivr.net/npm/lodash@2.4.1/dist/lodash.min.js', }], - auth: ['admin'], }; } diff --git a/examples/basic-project/src/pages/blog.tsx b/examples/basic-project/src/pages/blog.tsx index ad00c943e..2981f5a64 100644 --- a/examples/basic-project/src/pages/blog.tsx +++ b/examples/basic-project/src/pages/blog.tsx @@ -17,6 +17,5 @@ export default function Blog() { export const getConfig = defineGetConfig(() => { return { title: 'Blog', - auth: ['guest'], }; }); \ No newline at end of file diff --git a/examples/basic-project/src/pages/index.tsx b/examples/basic-project/src/pages/index.tsx index 0f35f9bff..4ec22b695 100644 --- a/examples/basic-project/src/pages/index.tsx +++ b/examples/basic-project/src/pages/index.tsx @@ -16,7 +16,6 @@ export default function Home(props) { const appData = useAppData<AppData>(); const data = useData(); const config = useConfig(); - if (typeof window !== 'undefined') { console.log('render Home', props); console.log('get AppData', appData); @@ -58,7 +57,6 @@ export function getConfig() { content: '#f00', }, ], - auth: ['admin'], }; } diff --git a/examples/basic-project/src/pages/layout.tsx b/examples/basic-project/src/pages/layout.tsx index 5fc650047..de4402233 100644 --- a/examples/basic-project/src/pages/layout.tsx +++ b/examples/basic-project/src/pages/layout.tsx @@ -23,7 +23,6 @@ export function getConfig() { content: '#f00', }, ], - auth: ['admin'], }; } diff --git a/examples/with-auth/ice.config.mts b/examples/with-auth/ice.config.mts new file mode 100644 index 000000000..c90b2379b --- /dev/null +++ b/examples/with-auth/ice.config.mts @@ -0,0 +1,8 @@ +import { defineConfig } from '@ice/app'; +import auth from '@ice/plugin-auth'; + +export default defineConfig({ + plugins: [ + auth(), + ], +}); diff --git a/examples/with-auth/package.json b/examples/with-auth/package.json new file mode 100644 index 000000000..dc2c6faec --- /dev/null +++ b/examples/with-auth/package.json @@ -0,0 +1,20 @@ +{ + "name": "with-auth", + "version": "1.0.0", + "scripts": { + "start": "ice start", + "build": "ice build" + }, + "license": "MIT", + "dependencies": { + "@ice/runtime": "workspace:*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "devDependencies": { + "@ice/app": "workspace:*", + "@ice/plugin-auth": "workspace:*", + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0" + } +} \ No newline at end of file diff --git a/examples/with-auth/src/app.tsx b/examples/with-auth/src/app.tsx new file mode 100644 index 000000000..d4d18d379 --- /dev/null +++ b/examples/with-auth/src/app.tsx @@ -0,0 +1,32 @@ +import { defineAppConfig, Link } from 'ice'; +import type { GetAppData } from 'ice'; +import { defineAuthConfig } from '@ice/plugin-auth/esm/types'; + +export default defineAppConfig({}); + +export const auth = defineAuthConfig((data) => { + // fetch auth data + return { + initialAuth: { + admin: data?.auth?.admin, + }, + NoAuthFallback: () => { + return ( + <> + <div id="no-auth">无权限访问</div> + <Link to="/">Home</Link> + </> + ); + }, + }; +}); + +export const getAppData: GetAppData = () => { + return new Promise((resolve) => { + resolve({ + auth: { + admin: true, + }, + }); + }); +}; \ No newline at end of file diff --git a/examples/with-auth/src/components/CustomAuth.tsx b/examples/with-auth/src/components/CustomAuth.tsx new file mode 100644 index 000000000..703856b7c --- /dev/null +++ b/examples/with-auth/src/components/CustomAuth.tsx @@ -0,0 +1,16 @@ +import { useAuth } from 'ice'; + +function CustomAuth({ children, authKey, fallback }) { + const [auth] = useAuth(); + // 判断是否有权限 + const hasAuth = auth[authKey]; + // 有权限时直接渲染内容 + if (hasAuth) { + return children; + } else { + // 无权限时显示指定 UI + return fallback || (<>No Auth</>); + } +} + +export default CustomAuth; diff --git a/examples/with-auth/src/document.tsx b/examples/with-auth/src/document.tsx new file mode 100644 index 000000000..eed51d789 --- /dev/null +++ b/examples/with-auth/src/document.tsx @@ -0,0 +1,22 @@ +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="with-auth" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <Scripts /> + </body> + </html> + ); +} + +export default Document; diff --git a/examples/with-auth/src/pages/blog.tsx b/examples/with-auth/src/pages/blog.tsx new file mode 100644 index 000000000..1d30391a3 --- /dev/null +++ b/examples/with-auth/src/pages/blog.tsx @@ -0,0 +1,17 @@ +import { defineGetConfig, Link } from 'ice'; + +export default function Blog() { + return ( + <> + <h1>Blog</h1> + <Link to="/">Index</Link> + </> + ); +} + +export const getConfig = defineGetConfig(() => { + return { + title: 'Blog', + auth: ['guest'], + }; +}); diff --git a/examples/with-auth/src/pages/index.tsx b/examples/with-auth/src/pages/index.tsx new file mode 100644 index 000000000..e403be701 --- /dev/null +++ b/examples/with-auth/src/pages/index.tsx @@ -0,0 +1,24 @@ +import { Link, useAuth, defineGetConfig } from 'ice'; +import CustomAuth from '@/components/CustomAuth'; + +export default function Index() { + const [, setAuth] = useAuth(); + return ( + <> + <ul style={{ listStyleType: 'none' }}> + <li><Link to="blog">Blog</Link></li> + </ul> + <h1>Index</h1> + <CustomAuth authKey={'guest'} fallback={<><div onClick={() => setAuth({ guest: true })}>Set Guest Auth</div>No Auth</>}> + I am ice.js. My auth is guest. + </CustomAuth> + </> + ); +} + +export const getConfig = defineGetConfig(() => { + return { + title: 'Index', + auth: ['admin'], + }; +}); diff --git a/examples/with-auth/tsconfig.json b/examples/with-auth/tsconfig.json new file mode 100644 index 000000000..6f2571086 --- /dev/null +++ b/examples/with-auth/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "module": "ESNext", + "target": "ESNext", + "lib": ["DOM", "ESNext", "DOM.Iterable"], + "jsx": "react-jsx", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": false, + "importHelpers": true, + "strictNullChecks": true, + "suppressImplicitAnyIndexErrors": true, + "skipLibCheck": true, + "paths": { + "@/*": ["./src/*"], + "ice": [".ice"] + } + }, + "include": ["src", ".ice"], + "exclude": ["build"] +} diff --git a/packages/plugin-auth/package.json b/packages/plugin-auth/package.json index 369029c90..d6f95cb29 100644 --- a/packages/plugin-auth/package.json +++ b/packages/plugin-auth/package.json @@ -20,11 +20,6 @@ "import": "./esm/runtime/index.js", "default": "./esm/runtime/index.js" }, - "./runtime/Auth": { - "types": "./esm/runtime/Auth.d.ts", - "import": "./esm/runtime/Auth.js", - "default": "./esm/runtime/Auth.js" - }, "./types": { "types": "./esm/types.d.ts", "import": "./esm/types.js", diff --git a/packages/plugin-auth/src/index.ts b/packages/plugin-auth/src/index.ts index 4489f5d48..08bc1751a 100644 --- a/packages/plugin-auth/src/index.ts +++ b/packages/plugin-auth/src/index.ts @@ -8,7 +8,7 @@ const plugin: Plugin = () => ({ // Register API: `import { useAuth, withAuth } from 'ice';` generator.addExport({ specifier: ['withAuth', 'useAuth'], - source: '@ice/plugin-auth/runtime/Auth', + source: '@ice/plugin-auth/esm/runtime', }); generator.addRouteTypes({ diff --git a/packages/plugin-auth/src/runtime/index.tsx b/packages/plugin-auth/src/runtime/index.tsx index 8d4e22813..e75acc6c0 100644 --- a/packages/plugin-auth/src/runtime/index.tsx +++ b/packages/plugin-auth/src/runtime/index.tsx @@ -1,14 +1,17 @@ import * as React from 'react'; import type { RuntimePlugin, AppProvider, RouteWrapper } from '@ice/runtime/esm/types'; import type { AuthConfig, AuthType, Auth } from '../types.js'; -import { AuthProvider, useAuth } from './Auth.js'; +import { AuthProvider, useAuth, withAuth } from './Auth.js'; import type { InjectProps } from './Auth.js'; +export { withAuth, useAuth }; + const runtime: RuntimePlugin = async ({ appContext, useConfig, addProvider, addWrapper }) => { const { appExport, appData } = appContext; const authConfig: AuthConfig = (typeof appExport.auth === 'function' ? (await appExport.auth(appData)) : appExport.auth) || {}; const initialAuth = authConfig.initialAuth || {}; + const AuthProviderWrapper: AppProvider = ({ children }) => { const [state, setState] = React.useState<AuthType>(initialAuth); @@ -20,6 +23,7 @@ const runtime: RuntimePlugin = async ({ appContext, useConfig, addProvider, addW }; return <AuthProvider value={[state, updateState]}>{children}</AuthProvider>; }; + addProvider(AuthProviderWrapper); const AuthRouteWrapper: RouteWrapper = ({ children }) => { const [auth] = useAuth(); @@ -47,9 +51,6 @@ const runtime: RuntimePlugin = async ({ appContext, useConfig, addProvider, addW return <>{children}</>; }; - - addProvider(AuthProviderWrapper); - addWrapper(AuthRouteWrapper); }; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0250439b0..30c825829 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -110,7 +110,6 @@ importers: examples/basic-project: specifiers: '@ice/app': workspace:* - '@ice/plugin-auth': workspace:* '@ice/plugin-rax-compat': workspace:* '@ice/runtime': workspace:* '@types/react': ^18.0.0 @@ -123,7 +122,6 @@ importers: webpack: ^5.73.0 dependencies: '@ice/app': link:../../packages/ice - '@ice/plugin-auth': link:../../packages/plugin-auth '@ice/plugin-rax-compat': link:../../packages/plugin-rax-compat '@ice/runtime': link:../../packages/runtime '@uni/env': 1.1.0 @@ -384,6 +382,25 @@ importers: '@types/react': 18.0.21 '@types/react-dom': 18.0.6 + examples/with-auth: + specifiers: + '@ice/app': workspace:* + '@ice/plugin-auth': workspace:* + '@ice/runtime': workspace:* + '@types/react': ^18.0.0 + '@types/react-dom': ^18.0.0 + react: ^18.0.0 + react-dom: ^18.0.0 + dependencies: + '@ice/runtime': link:../../packages/runtime + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + devDependencies: + '@ice/app': link:../../packages/ice + '@ice/plugin-auth': link:../../packages/plugin-auth + '@types/react': 18.0.21 + '@types/react-dom': 18.0.6 + examples/with-fusion: specifiers: '@alifd/next': ^1.25.49 diff --git a/tests/integration/with-auth.test.ts b/tests/integration/with-auth.test.ts new file mode 100644 index 000000000..f03bbbb7f --- /dev/null +++ b/tests/integration/with-auth.test.ts @@ -0,0 +1,59 @@ +import { expect, test, describe, afterAll } from 'vitest'; +import { buildFixture, setupBrowser } from '../utils/build'; +import { startFixture, setupStartBrowser } from '../utils/start'; +import type { Page } from '../utils/browser'; +import type Browser from '../utils/browser'; + +const example = 'with-auth'; + +describe(`build ${example}`, () => { + let page: Page; + let browser: Browser; + + test('open /', async () => { + await buildFixture(example); + const res = await setupBrowser({ example }); + + page = res.page; + browser = res.browser; + expect(await page.$$text('h1')).toStrictEqual(['Index']); + }, 120000); + + test('open /blog', async () => { + await page.push('/blog.html'); + expect(await page.$$text('#no-auth')).toStrictEqual(['无权限访问']); + }); + + afterAll(async () => { + await browser.close(); + }); +}); + +describe(`start ${example}`, () => { + let page: Page; + let browser: Browser; + + test('open /', async () => { + const { devServer, port } = await startFixture(example, { + mock: true, + force: true, + https: false, + analyzer: false, + open: false, + mode: 'start', + }); + const res = await setupStartBrowser({ server: devServer, port }); + page = res.page; + browser = res.browser; + expect(await page.$$text('h1')).toStrictEqual(['Index']); + }, 120000); + + test('open /blog', async () => { + await page.push('/blog'); + expect(await page.$$text('#no-auth')).toStrictEqual(['无权限访问']); + }); + + afterAll(async () => { + await browser.close(); + }); +}); diff --git a/website/docs/guide/advanced/auth.md b/website/docs/guide/advanced/auth.md index c1b136629..e6123e591 100644 --- a/website/docs/guide/advanced/auth.md +++ b/website/docs/guide/advanced/auth.md @@ -9,8 +9,8 @@ import TabItem from '@theme/TabItem'; <summary>示例</summary> <ul> <li> - <a href="https://github.com/ice-lab/ice-next/tree/master/examples/basic-project" target="_blank" rel="noopener noreferrer"> - basic-project + <a href="https://github.com/ice-lab/ice-next/tree/master/examples/with-auth" target="_blank" rel="noopener noreferrer"> + with-auth </a> </li> </ul> From 0fcbd4f0b8509df493fa8eeca46bb00877226dfc Mon Sep 17 00:00:00 2001 From: luhc228 <44047106+luhc228@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:53:42 +0800 Subject: [PATCH 19/22] refactor: hash router (#648) * feat: show hash router error * feat: support generate one html when ssg is false * fix: test case fail * fix: type * chore: revert renderDocument * fix: test fail * feat: generate one html when enable hash router * fix: type error * fix: test error * fix: comment --- packages/ice/src/commands/build.ts | 22 ++++- packages/ice/src/commands/start.ts | 1 + packages/ice/src/createService.ts | 2 + .../src/middlewares/ssr/renderMiddleware.ts | 23 ++++- packages/ice/src/plugins/web/index.ts | 6 +- packages/ice/src/types/plugin.ts | 4 +- packages/ice/src/utils/generateHTML.ts | 85 +++++++++++++------ .../ice/src/utils/warnOnHashRouterEnabled.ts | 8 ++ 8 files changed, 118 insertions(+), 33 deletions(-) create mode 100644 packages/ice/src/utils/warnOnHashRouterEnabled.ts diff --git a/packages/ice/src/commands/build.ts b/packages/ice/src/commands/build.ts index 6c008d3ef..68eed1c22 100644 --- a/packages/ice/src/commands/build.ts +++ b/packages/ice/src/commands/build.ts @@ -5,11 +5,14 @@ import webpack from '@ice/bundles/compiled/webpack/index.js'; import type { StatsError, Stats } from 'webpack'; import type { Config } from '@ice/webpack-config/esm/types'; import type ora from '@ice/bundles/compiled/ora/index.js'; +import type { AppConfig } from '@ice/runtime/esm/types'; import type { ServerCompiler, GetAppConfig, GetRoutesConfig, ExtendsPluginAPI } from '../types/plugin.js'; import webpackCompiler from '../service/webpackCompiler.js'; import formatWebpackMessages from '../utils/formatWebpackMessages.js'; import { RUNTIME_TMP_DIR } from '../constant.js'; import emptyDir from '../utils/emptyDir.js'; +import type { UserConfig } from '../types/userConfig.js'; +import warnOnHashRouterEnabled from '../utils/warnOnHashRouterEnabled.js'; const build = async ( context: Context<Config, ExtendsPluginAPI>, @@ -18,12 +21,28 @@ const build = async ( serverCompiler: ServerCompiler; spinner: ora.Ora; getAppConfig: GetAppConfig; + appConfig: AppConfig; getRoutesConfig: GetRoutesConfig; userConfigHash: string; + userConfig: UserConfig; }, ) => { - const { taskConfigs, serverCompiler, spinner, getAppConfig, getRoutesConfig, userConfigHash } = options; + const { + taskConfigs, + serverCompiler, + spinner, + getAppConfig, + appConfig, + getRoutesConfig, + userConfigHash, + userConfig, + } = options; const { applyHook, rootDir } = context; + + if (appConfig?.router?.type === 'hash') { + warnOnHashRouterEnabled(userConfig); + } + const webpackConfigs = taskConfigs.map(({ config }) => getWebpackConfig({ config, rootDir, @@ -97,6 +116,7 @@ const build = async ( serverEntryRef, getAppConfig, getRoutesConfig, + appConfig, }); return { compiler }; diff --git a/packages/ice/src/commands/start.ts b/packages/ice/src/commands/start.ts index 5c9d45a37..42a5b1716 100644 --- a/packages/ice/src/commands/start.ts +++ b/packages/ice/src/commands/start.ts @@ -139,6 +139,7 @@ async function startDevServer({ renderMode, getAppConfig, taskConfig: webTaskConfig, + userConfig, }); const insertIndex = middlewares.findIndex(({ name }) => name === 'serve-index'); middlewares.splice( diff --git a/packages/ice/src/createService.ts b/packages/ice/src/createService.ts index a939d35d5..fd83285c8 100644 --- a/packages/ice/src/createService.ts +++ b/packages/ice/src/createService.ts @@ -247,10 +247,12 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt return await build(ctx, { getRoutesConfig, getAppConfig, + appConfig, taskConfigs, serverCompiler, spinner: buildSpinner, userConfigHash, + userConfig, }); } else if (command === 'test') { return await test(ctx, { diff --git a/packages/ice/src/middlewares/ssr/renderMiddleware.ts b/packages/ice/src/middlewares/ssr/renderMiddleware.ts index 76d0c2379..1d3f94707 100644 --- a/packages/ice/src/middlewares/ssr/renderMiddleware.ts +++ b/packages/ice/src/middlewares/ssr/renderMiddleware.ts @@ -10,23 +10,38 @@ import type { Config } from '@ice/webpack-config/esm/types'; import type { ExtendsPluginAPI } from '../../types/plugin.js'; import getRouterBasename from '../../utils/getRouterBasename.js'; import dynamicImport from '../../utils/dynamicImport.js'; +import warnOnHashRouterEnabled from '../../utils/warnOnHashRouterEnabled.js'; +import type { UserConfig } from '../../types/userConfig.js'; const require = createRequire(import.meta.url); interface Options { serverCompileTask: ExtendsPluginAPI['serverCompileTask']; routeManifestPath: string; + getAppConfig: () => Promise<any>; + userConfig: UserConfig; documentOnly?: boolean; renderMode?: RenderMode; taskConfig?: TaskConfig<Config>; - getAppConfig: () => Promise<any>; } export default function createRenderMiddleware(options: Options): Middleware { - const { documentOnly, renderMode, serverCompileTask, routeManifestPath, getAppConfig, taskConfig } = options; + const { + documentOnly, + renderMode, + serverCompileTask, + routeManifestPath, + getAppConfig, + taskConfig, + userConfig, + } = options; const middleware: ExpressRequestHandler = async function (req, res, next) { const routes = JSON.parse(fse.readFileSync(routeManifestPath, 'utf-8')); - const basename = getRouterBasename(taskConfig, (await getAppConfig()).default); + const appConfig = (await getAppConfig()).default; + if (appConfig?.router?.type === 'hash') { + warnOnHashRouterEnabled(userConfig); + } + const basename = getRouterBasename(taskConfig, appConfig); const matches = matchRoutes(routes, req.path, basename); // When documentOnly is true, it means that the app is CSR and it should return the html. if (matches.length || documentOnly) { @@ -62,4 +77,4 @@ export default function createRenderMiddleware(options: Options): Middleware { name: 'server-render', middleware, }; -} \ No newline at end of file +} diff --git a/packages/ice/src/plugins/web/index.ts b/packages/ice/src/plugins/web/index.ts index a4fa6f206..dc07f6459 100644 --- a/packages/ice/src/plugins/web/index.ts +++ b/packages/ice/src/plugins/web/index.ts @@ -1,6 +1,7 @@ import * as path from 'path'; import consola from 'consola'; import chalk from 'chalk'; +import type { RenderMode } from '@ice/runtime'; import lodash from '@ice/bundles/compiled/lodash/index.js'; import type { Plugin } from '../../types/plugin.js'; import ReCompilePlugin from '../../webpack/ReCompilePlugin.js'; @@ -100,9 +101,9 @@ const plugin: Plugin = () => ({ } }); - onHook('after.build.compile', async ({ webpackConfigs, serverEntryRef }) => { + onHook('after.build.compile', async ({ webpackConfigs, serverEntryRef, appConfig }) => { const outputDir = webpackConfigs[0].output.path; - let renderMode; + let renderMode: RenderMode; if (ssg) { renderMode = 'SSG'; } @@ -115,6 +116,7 @@ const plugin: Plugin = () => ({ // only ssg need to generate the whole page html when build time. documentOnly: !ssg, renderMode, + routeType: appConfig?.router?.type, }); }); diff --git a/packages/ice/src/types/plugin.ts b/packages/ice/src/types/plugin.ts index 10162a6a6..9e4a5606e 100644 --- a/packages/ice/src/types/plugin.ts +++ b/packages/ice/src/types/plugin.ts @@ -4,7 +4,7 @@ import type { Configuration, Stats, WebpackOptionsNormalized } from '@ice/bundle import type { BuildOptions, BuildResult } from 'esbuild'; import type { NestedRouteManifest } from '@ice/route-manifest'; import type { Config } from '@ice/webpack-config/esm/types'; -import type { AssetsManifest } from '@ice/runtime/esm/types'; +import type { AppConfig, AssetsManifest } from '@ice/runtime/esm/types'; import type { DeclarationData, AddRenderFile, AddTemplateFiles, ModifyRenderData, AddDataLoaderImport, Render } from './generator.js'; type AddExport = (exportData: DeclarationData) => void; @@ -85,7 +85,7 @@ export interface HookLifecycle { 'before.start.run': BeforeCommandRunOptions; 'before.build.run': BeforeCommandRunOptions; 'after.start.compile': AfterCommandCompileOptions & { devUrlInfo?: DevServerInfo }; - 'after.build.compile': AfterCommandCompileOptions & { serverEntryRef: { current: string } }; + 'after.build.compile': AfterCommandCompileOptions & { serverEntryRef: { current: string }; appConfig: AppConfig }; 'after.start.devServer': { urls: Urls; devServer: WebpackOptionsNormalized['devServer']; diff --git a/packages/ice/src/utils/generateHTML.ts b/packages/ice/src/utils/generateHTML.ts index 6df6860bf..b3e9c9f24 100644 --- a/packages/ice/src/utils/generateHTML.ts +++ b/packages/ice/src/utils/generateHTML.ts @@ -2,7 +2,7 @@ import * as path from 'path'; import type { Request } from 'webpack-dev-server'; import fse from 'fs-extra'; import consola from 'consola'; -import type { ServerContext, RenderMode } from '@ice/runtime'; +import type { ServerContext, RenderMode, AppConfig } from '@ice/runtime'; import { ROUTER_MANIFEST } from '../constant.js'; import getRoutePaths from './getRoutePaths.js'; import dynamicImport from './dynamicImport.js'; @@ -12,6 +12,7 @@ interface Options { entry: string; outputDir: string; documentOnly: boolean; + routeType: AppConfig['router']['type']; renderMode?: RenderMode; } @@ -22,44 +23,80 @@ export default async function generateHTML(options: Options) { outputDir, documentOnly, renderMode, + routeType, } = options; let serverEntry; - try { serverEntry = await dynamicImport(entry); } catch (err) { // make error clearly, notice typeof err === 'string' throw new Error(`import ${entry} error: ${err}`); } + // Read the latest routes info. const routeManifest = path.join(rootDir, ROUTER_MANIFEST); const routes = JSON.parse(fse.readFileSync(routeManifest, 'utf8')); - const paths = getRoutePaths(routes); - + // When enable hash-router, only generate one html(index.html). + const paths = routeType === 'hash' ? ['/'] : getRoutePaths(routes); for (let i = 0, n = paths.length; i < n; i++) { const routePath = paths[i]; + const htmlContent = await renderHTML({ routePath, serverEntry, documentOnly, renderMode }); + await writeFile( + await generateHTMLPath({ rootDir, routePath, outputDir }), + htmlContent, + ); + } +} - const req = { - url: routePath, - }; +const writeFile = async (file: string, content: string) => { + await fse.ensureFile(file); + await fse.writeFile(file, content); +}; - const serverContext: ServerContext = { - req: req as Request, - }; - const { value: html } = await serverEntry.renderToHTML(serverContext, { - renderMode, - documentOnly, - routePath, - serverOnlyBasename: '/', - }); - // Win32 do not support file name with - const fileName = routePath === '/' ? 'index.html' : `${routePath.replace(/\/:/g, '/$')}.html`; - if (fse.existsSync(path.join(rootDir, 'public', fileName))) { - consola.warn(`${fileName} is overwrite by framework, rename file name if it is necessary`); - } - const contentPath = path.join(outputDir, fileName); - await fse.ensureFile(contentPath); - await fse.writeFile(contentPath, html); +async function generateHTMLPath( + { + rootDir, + routePath, + outputDir, + }: { + rootDir: string; + routePath: string; + outputDir: string; + }, +) { + // Win32 do not support file name with + const fileName = routePath === '/' ? 'index.html' : `${routePath.replace(/\/:/g, '/$')}.html`; + if (fse.existsSync(path.join(rootDir, 'public', fileName))) { + consola.warn(`${fileName} is overwrite by framework, rename file name if it is necessary.`); } + + return path.join(outputDir, fileName); +} + +async function renderHTML( + { + routePath, + serverEntry, + documentOnly, + renderMode, + }: { + routePath: string; + serverEntry: any; + documentOnly: boolean; + renderMode?: RenderMode; + }, +) { + const serverContext: ServerContext = { + req: { + url: routePath, + } as Request, + }; + const { value: html } = await serverEntry.renderToHTML(serverContext, { + renderMode, + documentOnly, + routePath, + serverOnlyBasename: '/', + }); + return html; } diff --git a/packages/ice/src/utils/warnOnHashRouterEnabled.ts b/packages/ice/src/utils/warnOnHashRouterEnabled.ts new file mode 100644 index 000000000..f19103314 --- /dev/null +++ b/packages/ice/src/utils/warnOnHashRouterEnabled.ts @@ -0,0 +1,8 @@ +import consola from 'consola'; +import type { UserConfig } from '../types/userConfig'; + +export default function warnOnHashRouterEnabled(userConfig: UserConfig) { + if (userConfig.ssr || userConfig.ssg) { + consola.warn('SSR and SSG are both enabled by default, but SSR and SSG is invalid in Hash Router. Please set "ssr: false" and "ssg: false" in your `ice.config.mts` file.'); + } +} From 082031081969afb0daf1a3badd11181cb3e4b71c Mon Sep 17 00:00:00 2001 From: luhc228 <44047106+luhc228@users.noreply.github.com> Date: Mon, 7 Nov 2022 13:57:06 +0800 Subject: [PATCH 20/22] feat: support postcss user config (#626) * feat: support postcss in userConfig * feat: support postcss.config.js * docs: optimize config * docs: postcss * feat: add tailwindcss example * chore: export postcss * docs: update postcss * docs: update browsers desc --- examples/with-tailwindcss/ice.config.mts | 9 ++ examples/with-tailwindcss/package.json | 19 +++ examples/with-tailwindcss/src/app.ts | 3 + examples/with-tailwindcss/src/document.tsx | 22 +++ examples/with-tailwindcss/src/global.css | 3 + examples/with-tailwindcss/src/pages/index.tsx | 7 + examples/with-tailwindcss/tailwind.config.js | 8 + examples/with-tailwindcss/tsconfig.json | 25 ++++ packages/bundles/src/index.ts | 2 + packages/ice/src/config.ts | 8 + packages/ice/src/types/userConfig.ts | 2 + packages/webpack-config/package.json | 1 + packages/webpack-config/src/config/css.ts | 86 +++++++---- packages/webpack-config/src/index.ts | 1 + packages/webpack-config/src/types.ts | 3 + pnpm-lock.yaml | 141 +++++++++++++++++- website/docs/guide/basic/config.md | 86 +++++++++-- 17 files changed, 388 insertions(+), 38 deletions(-) create mode 100644 examples/with-tailwindcss/ice.config.mts create mode 100644 examples/with-tailwindcss/package.json create mode 100644 examples/with-tailwindcss/src/app.ts create mode 100644 examples/with-tailwindcss/src/document.tsx create mode 100644 examples/with-tailwindcss/src/global.css create mode 100644 examples/with-tailwindcss/src/pages/index.tsx create mode 100644 examples/with-tailwindcss/tailwind.config.js create mode 100644 examples/with-tailwindcss/tsconfig.json diff --git a/examples/with-tailwindcss/ice.config.mts b/examples/with-tailwindcss/ice.config.mts new file mode 100644 index 000000000..eff084e5b --- /dev/null +++ b/examples/with-tailwindcss/ice.config.mts @@ -0,0 +1,9 @@ +import { defineConfig } from '@ice/app'; + +export default defineConfig({ + postcss: { + plugins: [ + 'tailwindcss', + ], + }, +}); diff --git a/examples/with-tailwindcss/package.json b/examples/with-tailwindcss/package.json new file mode 100644 index 000000000..089030923 --- /dev/null +++ b/examples/with-tailwindcss/package.json @@ -0,0 +1,19 @@ +{ + "name": "with-tailwindcss", + "version": "1.0.0", + "scripts": { + "start": "ice start", + "build": "ice build" + }, + "dependencies": { + "@ice/runtime": "workspace:*", + "react": "^18.0.0", + "react-dom": "^18.0.0" + }, + "devDependencies": { + "@types/react": "^18.0.0", + "@types/react-dom": "^18.0.0", + "@ice/app": "workspace:*", + "tailwindcss": "^3.2.1" + } +} \ No newline at end of file diff --git a/examples/with-tailwindcss/src/app.ts b/examples/with-tailwindcss/src/app.ts new file mode 100644 index 000000000..c1664902e --- /dev/null +++ b/examples/with-tailwindcss/src/app.ts @@ -0,0 +1,3 @@ +import { defineAppConfig } from 'ice'; + +export default defineAppConfig({}); diff --git a/examples/with-tailwindcss/src/document.tsx b/examples/with-tailwindcss/src/document.tsx new file mode 100644 index 000000000..e6753222f --- /dev/null +++ b/examples/with-tailwindcss/src/document.tsx @@ -0,0 +1,22 @@ +import { Meta, Title, Links, Main, Scripts } from 'ice'; + +function Document() { + return ( + <html> + <head> + <meta charSet="utf-8" /> + <meta name="description" content="with-web-worker" /> + <meta name="viewport" content="width=device-width, initial-scale=1" /> + <Meta /> + <Title /> + <Links /> + </head> + <body> + <Main /> + <Scripts /> + </body> + </html> + ); +} + +export default Document; diff --git a/examples/with-tailwindcss/src/global.css b/examples/with-tailwindcss/src/global.css new file mode 100644 index 000000000..b5c61c956 --- /dev/null +++ b/examples/with-tailwindcss/src/global.css @@ -0,0 +1,3 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; diff --git a/examples/with-tailwindcss/src/pages/index.tsx b/examples/with-tailwindcss/src/pages/index.tsx new file mode 100644 index 000000000..3827e559a --- /dev/null +++ b/examples/with-tailwindcss/src/pages/index.tsx @@ -0,0 +1,7 @@ +export default function Home() { + return ( + <h1 className="text-3xl font-bold underline"> + Hello world! + </h1> + ); +} diff --git a/examples/with-tailwindcss/tailwind.config.js b/examples/with-tailwindcss/tailwind.config.js new file mode 100644 index 000000000..fff160a06 --- /dev/null +++ b/examples/with-tailwindcss/tailwind.config.js @@ -0,0 +1,8 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./src/**/*.{js,jsx,ts,tsx}'], + theme: { + extend: {}, + }, + plugins: [], +}; \ No newline at end of file diff --git a/examples/with-tailwindcss/tsconfig.json b/examples/with-tailwindcss/tsconfig.json new file mode 100644 index 000000000..b15003550 --- /dev/null +++ b/examples/with-tailwindcss/tsconfig.json @@ -0,0 +1,25 @@ +{ + "compilerOptions": { + "baseUrl": "./", + "module": "ESNext", + "target": "ESNext", + "lib": ["DOM", "ESNext", "DOM.Iterable"], + "jsx": "react-jsx", + "moduleResolution": "node", + "allowSyntheticDefaultImports": true, + "forceConsistentCasingInFileNames": true, + "noImplicitReturns": true, + "noImplicitThis": true, + "noImplicitAny": false, + "importHelpers": true, + "strictNullChecks": true, + "suppressImplicitAnyIndexErrors": true, + "skipLibCheck": true, + "paths": { + "@/*": ["./src/*"], + "ice": [".ice"] + } + }, + "include": ["src", ".ice"], + "exclude": ["build"] +} \ No newline at end of file diff --git a/packages/bundles/src/index.ts b/packages/bundles/src/index.ts index c46aef356..4e3d9b550 100644 --- a/packages/bundles/src/index.ts +++ b/packages/bundles/src/index.ts @@ -8,3 +8,5 @@ export { less, sass, }; + +export type { ProcessOptions } from 'postcss'; diff --git a/packages/ice/src/config.ts b/packages/ice/src/config.ts index 4c9029964..c166cccdc 100644 --- a/packages/ice/src/config.ts +++ b/packages/ice/src/config.ts @@ -138,6 +138,14 @@ const userConfig = [ } }, }, + { + name: 'postcss', + validation: 'object', + defaultValue: {}, + setConfig(config: Config, postcss: UserConfig['postcss']) { + return mergeDefaultValue(config, 'postcss', postcss); + }, + }, { name: 'webpack', validation: 'function', diff --git a/packages/ice/src/types/userConfig.ts b/packages/ice/src/types/userConfig.ts index 4a9559875..d90a3a9f7 100644 --- a/packages/ice/src/types/userConfig.ts +++ b/packages/ice/src/types/userConfig.ts @@ -1,6 +1,7 @@ import type { DefineRouteFunction } from '@ice/route-manifest'; import type { PluginList } from 'build-scripts'; import type { UnpluginOptions } from '@ice/bundles/compiled/unplugin/index.js'; +import type { ProcessOptions } from '@ice/bundles'; import type { Config, ModifyWebpackConfig, MinimizerOptions } from '@ice/webpack-config/esm/types'; import type { OverwritePluginAPI } from './plugin'; @@ -36,6 +37,7 @@ export interface UserConfig { polyfill?: Config['polyfill']; filename?: string; webpack?: ModifyWebpackConfig; + postcss?: ProcessOptions & { plugins?: (string | [string, Record<string, any>?])[] }; routes?: { ignoreFiles?: string[]; defineRoutes?: (defineRoute: DefineRouteFunction) => void; diff --git a/packages/webpack-config/package.json b/packages/webpack-config/package.json index 072eda323..94d5bb2af 100644 --- a/packages/webpack-config/package.json +++ b/packages/webpack-config/package.json @@ -26,6 +26,7 @@ }, "devDependencies": { "esbuild": "^0.14.51", + "postcss": "^8.4.18", "webpack": "^5.73.0", "webpack-dev-server": "^4.7.4" }, diff --git a/packages/webpack-config/src/config/css.ts b/packages/webpack-config/src/config/css.ts index ca2aff015..47fd01933 100644 --- a/packages/webpack-config/src/config/css.ts +++ b/packages/webpack-config/src/config/css.ts @@ -1,21 +1,28 @@ import { createRequire } from 'module'; import { createHash } from 'crypto'; +import * as path from 'path'; +import * as fs from 'fs'; // FIXME when resolve mini-css-extract-plugin symbol in test import MiniCssExtractPlugin from '@ice/bundles/compiled/mini-css-extract-plugin/dist/index.js'; import { sass, less, postcss } from '@ice/bundles'; import type webpack from 'webpack'; import type { LoaderContext, Configuration } from 'webpack'; -import type { ModifyWebpackConfig } from '../types.js'; +import lodash from '@ice/bundles/compiled/lodash/index.js'; +import type { ModifyWebpackConfig, Config } from '../types.js'; + +const { mergeWith, isArray } = lodash; type CSSRuleConfig = [string, string?, Record<string, any>?]; interface Options { publicPath: string; + postcssOptions: Config['postcss']; + rootDir: string; } const require = createRequire(import.meta.url); function configCSSRule(config: CSSRuleConfig, options: Options) { - const { publicPath } = options; + const { publicPath, rootDir, postcssOptions: userPostcssOptions } = options; const [style, loader, loaderOptions] = config; const cssLoaderOpts = { sourceMap: true, @@ -39,28 +46,7 @@ function configCSSRule(config: CSSRuleConfig, options: Options) { }, }, }; - const postcssOpts = { - // lock postcss version - implementation: postcss, - postcssOptions: { - config: false, - plugins: [ - ['@ice/bundles/compiled/postcss-nested'], - ['@ice/bundles/compiled/postcss-preset-env', { - // Without any configuration options, PostCSS Preset Env enables Stage 2 features. - stage: 3, - autoprefixer: { - // Disable legacy flexbox support - flexbox: 'no-2009', - }, - features: { - 'custom-properties': false, - }, - }], - ['@ice/bundles/compiled/postcss-plugin-rpx2vw'], - ], - }, - }; + const postcssOpts = getPostcssOpts({ rootDir, userPostcssOptions }); return { test: new RegExp(`\\.${style}$`), use: [ @@ -92,7 +78,7 @@ function configCSSRule(config: CSSRuleConfig, options: Options) { } const css: ModifyWebpackConfig<Configuration, typeof webpack> = (config, ctx) => { - const { publicPath, hashKey, cssFilename, cssChunkFilename } = ctx; + const { publicPath, hashKey, cssFilename, cssChunkFilename, postcss, rootDir } = ctx; const cssOutputFolder = 'css'; config.module.rules.push(...([ ['css'], @@ -103,7 +89,7 @@ const css: ModifyWebpackConfig<Configuration, typeof webpack> = (config, ctx) => ['scss', require.resolve('@ice/bundles/compiled/sass-loader'), { implementation: sass, }], - ] as CSSRuleConfig[]).map((config) => configCSSRule(config, { publicPath }))); + ] as CSSRuleConfig[]).map((config) => configCSSRule(config, { publicPath, postcssOptions: postcss, rootDir }))); config.plugins.push( new MiniCssExtractPlugin({ filename: cssFilename || `${cssOutputFolder}/${hashKey ? `[name]-[${hashKey}].css` : '[name].css'}`, @@ -116,4 +102,52 @@ const css: ModifyWebpackConfig<Configuration, typeof webpack> = (config, ctx) => return config; }; +function getPostcssOpts({ + rootDir, + userPostcssOptions, +}: { + rootDir: string; + userPostcssOptions: Options['postcssOptions']; +}) { + const postcssConfigPath = path.join(rootDir, 'postcss.config.js'); + const defaultPostcssOpts = { + // lock postcss version + implementation: postcss, + }; + if (fs.existsSync(postcssConfigPath)) { + return defaultPostcssOpts; + } else { + const postcssOpts = mergeWith( + { + ...defaultPostcssOpts, + postcssOptions: { + config: false, + plugins: [ + ['@ice/bundles/compiled/postcss-nested'], + ['@ice/bundles/compiled/postcss-preset-env', { + // Without any configuration options, PostCSS Preset Env enables Stage 2 features. + stage: 3, + autoprefixer: { + // Disable legacy flexbox support + flexbox: 'no-2009', + }, + features: { + 'custom-properties': false, + }, + }], + ['@ice/bundles/compiled/postcss-plugin-rpx2vw'], + ], + }, + }, + { postcssOptions: userPostcssOptions }, + (objValue, srcValue) => { + if (isArray(objValue)) { + return objValue.concat(srcValue); + } + }, + ); + return postcssOpts; + } +} + export default css; diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index fd9772b7b..877462ba0 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -399,6 +399,7 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT // pipe webpack by built-in functions and custom functions const ctx = { ...config, + rootDir, hashKey, webpack, }; diff --git a/packages/webpack-config/src/types.ts b/packages/webpack-config/src/types.ts index 6a96bc788..50926f08a 100644 --- a/packages/webpack-config/src/types.ts +++ b/packages/webpack-config/src/types.ts @@ -13,6 +13,7 @@ import type { UnpluginOptions, UnpluginContext } from '@ice/bundles/compiled/unp import type Server from 'webpack-dev-server'; import type { Config as SWCCompilationConfig } from '@swc/core'; import type { BuildOptions } from 'esbuild'; +import type { ProcessOptions } from 'postcss'; export type ECMA = 5 | 2015 | 2016 | 2017 | 2018 | 2019 | 2020; @@ -30,6 +31,7 @@ export type MinimizerOptions<T> = PredefinedOptions & InferDefaultType<T>; interface ConfigurationCtx<T = typeof webpack> extends Config { hashKey: string; webpack: T; + rootDir: string; } type Experimental = Configuration['experiments']; @@ -164,6 +166,7 @@ export interface Config { cssChunkFilename?: string; + postcss?: ProcessOptions & { plugins?: (string | [string, Record<string, any>?])[] }; enableCopyPlugin?: boolean; getAppConfig?: (exportNamse?: string[]) => Promise<any>; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 30c825829..8b6ce876d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -514,6 +514,25 @@ importers: '@types/react-dom': 18.0.6 tslib: 2.4.0 + examples/with-tailwindcss: + specifiers: + '@ice/app': workspace:* + '@ice/runtime': workspace:* + '@types/react': ^18.0.0 + '@types/react-dom': ^18.0.0 + react: ^18.0.0 + react-dom: ^18.0.0 + tailwindcss: ^3.2.1 + dependencies: + '@ice/runtime': link:../../packages/runtime + react: 18.2.0 + react-dom: 18.2.0_react@18.2.0 + devDependencies: + '@ice/app': link:../../packages/ice + '@types/react': 18.0.21 + '@types/react-dom': 18.0.6 + tailwindcss: 3.2.1 + examples/with-vitest: specifiers: '@ice/app': workspace:* @@ -1171,6 +1190,7 @@ importers: consola: ^2.15.3 esbuild: ^0.14.51 fast-glob: ^3.2.11 + postcss: ^8.4.18 webpack: ^5.73.0 webpack-dev-server: ^4.7.4 dependencies: @@ -1184,6 +1204,7 @@ importers: fast-glob: 3.2.12 devDependencies: esbuild: 0.14.54 + postcss: 8.4.18 webpack: 5.74.0_erwzf5wtj3ezvtz6x57nwwsumu webpack-dev-server: 4.11.1_webpack@5.74.0 @@ -6786,7 +6807,6 @@ packages: /arg/5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} - dev: false /argparse/1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -8782,6 +8802,10 @@ packages: resolution: {integrity: sha512-0cuGS8+jhR67Fy7qG3i3Pc7Aw494sb9yG9QgpG97SFVWwolgYjlhJg7n+UaHxOQT30d1TYu/EYe9k01ivLErIg==} dev: true + /didyoumean/1.2.2: + resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + dev: true + /diff-sequences/28.1.1: resolution: {integrity: sha512-FU0iFaH/E23a+a718l8Qa/19bF9p06kgE0KipMOMadwa3SjnaElKzPaUC0vnibs6/B/9ni97s61mcejk8W1fQw==} engines: {node: ^12.13.0 || ^14.15.0 || ^16.10.0 || >=17.0.0} @@ -8803,6 +8827,10 @@ packages: dependencies: path-type: 4.0.0 + /dlv/1.1.3: + resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + dev: true + /dns-equal/1.0.0: resolution: {integrity: sha512-z+paD6YUQsk+AbGCEM4PrOXSss5gd66QfcVBFTKR/HpFL9jCqikS94HYwKww6fQyO7IxrIIyUu+g0Ka9tUS2Cg==} @@ -13615,6 +13643,11 @@ packages: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} + /object-hash/3.0.0: + resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} + engines: {node: '>= 6'} + dev: true + /object-inspect/1.12.2: resolution: {integrity: sha512-z+cPxW0QGUp0mcqcsgQyLVRDoXFQbXOwBaqyF7VIgI4TWNQsDHrBpUQslRmIfAoYWdYzs6UlKJtB2XJpTaNSpQ==} @@ -13984,6 +14017,11 @@ packages: hasBin: true dev: true + /pify/2.3.0: + resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} + engines: {node: '>=0.10.0'} + dev: true + /pify/4.0.1: resolution: {integrity: sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==} engines: {node: '>=6'} @@ -14322,6 +14360,18 @@ packages: postcss-value-parser: 4.2.0 dev: true + /postcss-import/14.1.0_postcss@8.4.18: + resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} + engines: {node: '>=10.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.18 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.1 + dev: true + /postcss-initial/4.0.1_postcss@8.4.12: resolution: {integrity: sha512-0ueD7rPqX8Pn1xJIjay0AZeIuDoF+V+VvMt/uOnn+4ezUKhZM/NokDeP6DwMNyIoYByuN/94IQnt5FEkaN59xQ==} peerDependencies: @@ -14330,6 +14380,16 @@ packages: postcss: 8.4.12 dev: true + /postcss-js/4.0.0_postcss@8.4.18: + resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.3.3 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.18 + dev: true + /postcss-lab-function/4.2.1_postcss@8.4.12: resolution: {integrity: sha512-xuXll4isR03CrQsmxyz92LJB2xX9n+pZJ5jE9JgcnmsCammLyKdlzrBin+25dy6wIjfhJpKBAN80gsTlCgRk2w==} engines: {node: ^12 || ^14 || >=16} @@ -14367,6 +14427,23 @@ packages: yaml: 1.10.2 dev: true + /postcss-load-config/3.1.4_postcss@8.4.18: + resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} + engines: {node: '>= 10'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 2.0.6 + postcss: 8.4.18 + yaml: 1.10.2 + dev: true + /postcss-loader/6.2.1_l7cnarxuwtifxq3zndacrkp2tq: resolution: {integrity: sha512-WbbYpmAaKcux/P66bZ40bpWsBucjx/TTgVVzRZ9yUO8yQfVBlameJ0ZGVaPfH64hNSBh63a+ICP5nqOpBA0w+Q==} engines: {node: '>= 12.13.0'} @@ -14676,6 +14753,16 @@ packages: postcss-selector-parser: 6.0.10 dev: true + /postcss-nested/6.0.0_postcss@8.4.18: + resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==} + engines: {node: '>=12.0'} + peerDependencies: + postcss: ^8.2.14 + dependencies: + postcss: 8.4.18 + postcss-selector-parser: 6.0.10 + dev: true + /postcss-nesting/10.2.0_postcss@8.4.12: resolution: {integrity: sha512-EwMkYchxiDiKUhlJGzWsD9b2zvq/r2SSubcRrgP+jujMXFzqvANLt16lJANC+5uZ6hjI7lpRmI6O8JIl+8l1KA==} engines: {node: ^12 || ^14 || >=16} @@ -15163,6 +15250,15 @@ packages: picocolors: 1.0.0 source-map-js: 1.0.2 + /postcss/8.4.18: + resolution: {integrity: sha512-Wi8mWhncLJm11GATDaQKobXSNEYGUHeQLiQqDFG1qQ5UTDPTEvKw0Xt5NsTpktGTwLps3ByrWsBrG0rB8YQ9oA==} + engines: {node: ^10 || ^12 || >=14} + dependencies: + nanoid: 3.3.4 + picocolors: 1.0.0 + source-map-js: 1.0.2 + dev: true + /prelude-ls/1.1.2: resolution: {integrity: sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w==} engines: {node: '>= 0.8.0'} @@ -15377,6 +15473,11 @@ packages: engines: {node: '>=8'} dev: true + /quick-lru/5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + engines: {node: '>=10'} + dev: true + /random-int/2.0.1: resolution: {integrity: sha512-YALjWK2Rt9EMIv9BF/3mvlzFWQathsvb5UZmN1QmhfIOfcQYXc/UcLzg0ablqesSBpBVLt2Tlwv/eTuBh4LXUQ==} engines: {node: '>=8'} @@ -16283,6 +16384,12 @@ packages: dependencies: loose-envify: 1.4.0 + /read-cache/1.0.0: + resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + dependencies: + pify: 2.3.0 + dev: true + /read-package-json/2.1.2: resolution: {integrity: sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA==} dependencies: @@ -17674,6 +17781,38 @@ packages: strip-ansi: 6.0.1 dev: true + /tailwindcss/3.2.1: + resolution: {integrity: sha512-Uw+GVSxp5CM48krnjHObqoOwlCt5Qo6nw1jlCRwfGy68dSYb/LwS9ZFidYGRiM+w6rMawkZiu1mEMAsHYAfoLg==} + engines: {node: '>=12.13.0'} + hasBin: true + dependencies: + arg: 5.0.2 + chokidar: 3.5.3 + color-name: 1.1.4 + detective: 5.2.1 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.2.12 + glob-parent: 6.0.2 + is-glob: 4.0.3 + lilconfig: 2.0.6 + micromatch: 4.0.5 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.0.0 + postcss: 8.4.18 + postcss-import: 14.1.0_postcss@8.4.18 + postcss-js: 4.0.0_postcss@8.4.18 + postcss-load-config: 3.1.4_postcss@8.4.18 + postcss-nested: 6.0.0_postcss@8.4.18 + postcss-selector-parser: 6.0.10 + postcss-value-parser: 4.2.0 + quick-lru: 5.1.1 + resolve: 1.22.1 + transitivePeerDependencies: + - ts-node + dev: true + /tapable/1.1.3: resolution: {integrity: sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==} engines: {node: '>=6'} diff --git a/website/docs/guide/basic/config.md b/website/docs/guide/basic/config.md index a1eedaba7..41c1ca538 100644 --- a/website/docs/guide/basic/config.md +++ b/website/docs/guide/basic/config.md @@ -101,11 +101,11 @@ console.log(process.env.TEST); #### dataLoader -是否启用内置的数据预加载能力 - - 类型 `boolean` - 默认值 `true` +是否启用内置的数据预加载能力。 + ### publicPath - 类型:`string` @@ -122,8 +122,8 @@ console.log(process.env.TEST); ### hash -类型:`boolean | string` -默认值:`false` +- 类型:`boolean | string` +- 默认值:`false` 如果希望构建后的资源带 hash 版本,可以将 hash 设置为 `true`,也可以设置为 `contenthash` 按文件内容生成 hash 值: @@ -137,8 +137,8 @@ export default defineConfig({ ### externals -类型:`Record<string, string>` -默认值:`{}` +- 类型:`Record<string, string>` +- 默认值:`{}` 设置哪些模块不打包,转而通过 `<script>` 或其他方式引入,比如: @@ -174,8 +174,8 @@ export default Document; ### outputDir -类型:`string` -默认值:`build` +- 类型:`string` +- 默认值:`build` 构建产物输出目录,默认为 `build` 目录 @@ -241,12 +241,72 @@ export default defineConfig({ }); ``` +### postcss + +- 类型:`ProcessOptions & { plugins?: (string | [string, Record<string, any>?])[] };` +- 默认值:`{}` + +用于添加 postcss 自定义配置。示例如下: + +```ts +import { defineConfig } from '@ice/app'; + +export default defineConfig({ + postcss: { + plugins: [ + 'postcss-px-to-viewport-8-plugin', + { + // ... + }, + ], + syntax: 'sugarss', + } +}); +``` + +ice.js 内置的 postcss 配置是: + +```json +{ + "plugins": [ + ["postcss-nested"], + ["postcss-preset-env", { + "stage": 3, + "autoprefixer": { + "flexbox": "no-2009", + }, + "features": { + "custom-properties": false, + }, + }], + ["postcss-plugin-rpx2vw"], + ], +} +``` + +如果需要完全重写 postcss 配置或修改内置的 postcss 配置,需要在项目根目录下新增 `postcss.config.js` 文件并加入配置,工程上会清空内置的 postcss 配置。 + +```js title="postcss.config.js" +module.exports = { + plugins: [ + [ + 'postcss-preset-env', + // 修改 postcss-preset-env 的选项 + { + stage: 2, + } + ] + ], +} +``` + ### polyfill - 类型:`'usage' | 'entry' | false` - 默认值:`false` 框架提供了多种 polyfill 的方式,开发者可以按实际情况选择对应的设置: + - `usage` 按开发者使用的语法自动引入对应的 `polyfill`,适用于 `node_modules` 也进行编译的场景(一定程度上影响编译效率以及三方依赖二次编译造成的代码冗余) - `entry` 自动引入 browser(浏览器)需要兼容的 `polyfill`,适用于 `node_modules` 依赖不进行编译的场景(可能存在大量未被使用的 `polyfill` 被引入) @@ -326,8 +386,9 @@ export default defineConfig({ ``` 其中: -* resourceRegExp 对应文件的匹配路径 -* contextRegExp (可选)对应文件内容的匹配规则 + +- resourceRegExp 对应文件的匹配路径 +- contextRegExp (可选)对应文件内容的匹配规则 ### routes @@ -433,6 +494,10 @@ export default defineConfig({ ### webpack +:::tip +ice.js 对 webpack 构建配置进行了定制,并借助 esbuild 等工具提升用户开发体验,直接修改 webpack 配置的方式并不推荐。 +::: + - 类型:`(config: WebpackConfig, taskConfig: TaskConfig) => WebpackConfig` - 默认值:`true` @@ -453,5 +518,4 @@ export default defineConfig({ }); ``` -> ice.js 对 webpack 构建配置进行了定制,并借助 esbuild 等工具提升用户开发体验,直接修改 webpack 配置的方式并不推荐。 > 如有定制需求欢迎👏 PR 或反馈:<https://github.com/alibaba/ice/issues> From 98ff4a04b85ab86d2c354ba1d86a029e49e4534e Mon Sep 17 00:00:00 2001 From: luhc228 <44047106+luhc228@users.noreply.github.com> Date: Mon, 7 Nov 2022 14:55:41 +0800 Subject: [PATCH 21/22] fix: fail to pre-bundle deps (#660) * fix: fail to pre bundle deps which has css * fix: import pre-bundle deps when pre-bundle failed --- packages/ice/src/service/preBundleCJSDeps.ts | 15 ++++++++++++++- packages/ice/src/service/serverCompiler.ts | 18 ++++-------------- packages/webpack-config/src/config/css.ts | 14 ++------------ packages/webpack-config/src/index.ts | 2 ++ .../src/utils/getCSSModuleLocalIdent.ts | 15 +++++++++++++++ 5 files changed, 37 insertions(+), 27 deletions(-) create mode 100644 packages/webpack-config/src/utils/getCSSModuleLocalIdent.ts diff --git a/packages/ice/src/service/preBundleCJSDeps.ts b/packages/ice/src/service/preBundleCJSDeps.ts index 074f1bfd6..68ef74117 100644 --- a/packages/ice/src/service/preBundleCJSDeps.ts +++ b/packages/ice/src/service/preBundleCJSDeps.ts @@ -8,11 +8,15 @@ import { resolve as resolveExports } from 'resolve.exports'; import moduleLexer from '@ice/bundles/compiled/es-module-lexer/index.js'; import type { Config } from '@ice/webpack-config/esm/types'; import type { TaskConfig } from 'build-scripts'; +import { getCSSModuleLocalIdent } from '@ice/webpack-config'; import flattenId from '../utils/flattenId.js'; import formatPath from '../utils/formatPath.js'; import { BUILDIN_CJS_DEPS, BUILDIN_ESM_DEPS } from '../constant.js'; import type { DepScanData } from '../esbuild/scan.js'; import aliasPlugin from '../esbuild/alias.js'; +import emptyCSSPlugin from '../esbuild/emptyCSS.js'; +import cssModulesPlugin from '../esbuild/cssModules.js'; +import escapeLocalIdent from '../utils/escapeLocalIdent.js'; interface DepInfo { file: string; @@ -25,7 +29,7 @@ export interface DepsMetaData { } interface PreBundleDepsResult { - metadata: DepsMetaData; + metadata?: DepsMetaData; } interface PreBundleDepsOptions { @@ -91,7 +95,15 @@ export default async function preBundleCJSDeps(options: PreBundleDepsOptions): P loader: { '.js': 'jsx' }, ignoreAnnotations: true, plugins: [ + emptyCSSPlugin(), aliasPlugin({ alias, format: 'cjs', externalDependencies: false }), + cssModulesPlugin({ + extract: false, + generateLocalIdentName: function (name: string, filename: string) { + // Compatible with webpack css-loader. + return escapeLocalIdent(getCSSModuleLocalIdent(filename, name)); + }, + }), ...plugins, ], external: [...BUILDIN_CJS_DEPS, ...BUILDIN_ESM_DEPS], @@ -99,6 +111,7 @@ export default async function preBundleCJSDeps(options: PreBundleDepsOptions): P } catch (error) { consola.error('Failed to bundle dependencies.'); consola.debug(error); + return {}; } await fse.writeJSON(metadataJSONPath, metadata, { spaces: 2 }); diff --git a/packages/ice/src/service/serverCompiler.ts b/packages/ice/src/service/serverCompiler.ts index aae6cbfe8..30e2622fd 100644 --- a/packages/ice/src/service/serverCompiler.ts +++ b/packages/ice/src/service/serverCompiler.ts @@ -1,11 +1,10 @@ import * as path from 'path'; -import { createHash } from 'crypto'; import consola from 'consola'; import esbuild from 'esbuild'; import type { Config } from '@ice/webpack-config/esm/types'; import lodash from '@ice/bundles/compiled/lodash/index.js'; import type { TaskConfig } from 'build-scripts'; -import { getCompilerPlugins } from '@ice/webpack-config'; +import { getCompilerPlugins, getCSSModuleLocalIdent } from '@ice/webpack-config'; import type { ServerCompiler } from '../types/plugin.js'; import type { UserConfig } from '../types/userConfig.js'; import escapeLocalIdent from '../utils/escapeLocalIdent.js'; @@ -132,17 +131,8 @@ export function createServerCompiler(options: Options) { cssModulesPlugin({ extract: false, generateLocalIdentName: function (name: string, filename: string) { - const hash = createHash('md4'); - hash.update(Buffer.from(filename + name, 'utf8')); - const localIdentHash = hash.digest('base64') - // Remove all leading digits - .replace(/^\d+/, '') - // Replace all slashes with underscores (same as in base64url) - .replace(/\//g, '_') - // Remove everything that is not an alphanumeric or underscore - .replace(/[^A-Za-z0-9_]+/g, '') - .slice(0, 8); - return escapeLocalIdent(`${name}--${localIdentHash}`); + // Compatible with webpack css-loader. + return escapeLocalIdent(getCSSModuleLocalIdent(filename, name)); }, }), assetsManifest && createAssetsPlugin(assetsManifest, rootDir), @@ -150,7 +140,7 @@ export function createServerCompiler(options: Options) { plugins: [ ...transformPlugins, // Plugin transformImportPlugin need after transformPlugins in case of it has onLoad lifecycle. - dev && preBundle && transformImportPlugin( + dev && preBundle && depsMetadata && transformImportPlugin( depsMetadata, path.join(rootDir, task.config.outputDir, SERVER_OUTPUT_DIR), ), diff --git a/packages/webpack-config/src/config/css.ts b/packages/webpack-config/src/config/css.ts index 47fd01933..5e51a80db 100644 --- a/packages/webpack-config/src/config/css.ts +++ b/packages/webpack-config/src/config/css.ts @@ -1,5 +1,4 @@ import { createRequire } from 'module'; -import { createHash } from 'crypto'; import * as path from 'path'; import * as fs from 'fs'; // FIXME when resolve mini-css-extract-plugin symbol in test @@ -8,6 +7,7 @@ import { sass, less, postcss } from '@ice/bundles'; import type webpack from 'webpack'; import type { LoaderContext, Configuration } from 'webpack'; import lodash from '@ice/bundles/compiled/lodash/index.js'; +import { getCSSModuleLocalIdent } from '../utils/getCSSModuleLocalIdent.js'; import type { ModifyWebpackConfig, Config } from '../types.js'; const { mergeWith, isArray } = lodash; @@ -32,17 +32,7 @@ function configCSSRule(config: CSSRuleConfig, options: Options) { modules: { auto: (resourcePath: string) => resourcePath.endsWith(`.module.${style}`), getLocalIdent: (context: LoaderContext<any>, localIdentName: string, localName: string) => { - const hash = createHash('md4'); - hash.update(Buffer.from(context.resourcePath + localName, 'utf8')); - const localIdentHash = hash.digest('base64') - // Remove all leading digits - .replace(/^\d+/, '') - // Replace all slashes with underscores (same as in base64url) - .replace(/\//g, '_') - // Remove everything that is not an alphanumeric or underscore - .replace(/[^A-Za-z0-9_]+/g, '') - .slice(0, 8); - return `${localName}--${localIdentHash}`; + return getCSSModuleLocalIdent(context.resourcePath, localName); }, }, }; diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index 877462ba0..422fd2ecc 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -22,6 +22,8 @@ import getSplitChunksConfig, { FRAMEWORK_BUNDLES } from './config/splitChunks.js import compilationPlugin from './unPlugins/compilation.js'; import compileExcludes from './compileExcludes.js'; +export { getCSSModuleLocalIdent } from './utils/getCSSModuleLocalIdent.js'; + const require = createRequire(import.meta.url); const { merge } = lodash; const { BundleAnalyzerPlugin } = bundleAnalyzer; diff --git a/packages/webpack-config/src/utils/getCSSModuleLocalIdent.ts b/packages/webpack-config/src/utils/getCSSModuleLocalIdent.ts new file mode 100644 index 000000000..f10b12dbc --- /dev/null +++ b/packages/webpack-config/src/utils/getCSSModuleLocalIdent.ts @@ -0,0 +1,15 @@ +import { createHash } from 'crypto'; + +export function getCSSModuleLocalIdent(filename: string, localName: string) { + const hash = createHash('md4'); + hash.update(Buffer.from(filename + localName, 'utf8')); + const localIdentHash = hash.digest('base64') + // Remove all leading digits + .replace(/^\d+/, '') + // Replace all slashes with underscores (same as in base64url) + .replace(/\//g, '_') + // Remove everything that is not an alphanumeric or underscore + .replace(/[^A-Za-z0-9_]+/g, '') + .slice(0, 8); + return `${localName}--${localIdentHash}`; +} From e8ad84c7464ce235386f4db6fffac07661a455dc Mon Sep 17 00:00:00 2001 From: ClarkXia <xiawenwu41@gmail.com> Date: Mon, 7 Nov 2022 16:56:01 +0800 Subject: [PATCH 22/22] fix: add process support for undefined env variables (#668) --- examples/basic-project/src/app.tsx | 1 + packages/webpack-config/package.json | 3 ++- packages/webpack-config/src/index.ts | 3 +++ pnpm-lock.yaml | 7 +++++++ 4 files changed, 13 insertions(+), 1 deletion(-) diff --git a/examples/basic-project/src/app.tsx b/examples/basic-project/src/app.tsx index 1482f3d02..9528c41b8 100644 --- a/examples/basic-project/src/app.tsx +++ b/examples/basic-project/src/app.tsx @@ -10,6 +10,7 @@ console.log('__LOG__'); console.warn('__WARN__'); console.error('__ERROR__'); console.log('process.env.HAHA', process.env.HAHA); +console.log('process.env.undefinedEnv', process.env.undefinedEnv); if (isWeb) { console.error('__IS_WEB__'); diff --git a/packages/webpack-config/package.json b/packages/webpack-config/package.json index 94d5bb2af..72469b0db 100644 --- a/packages/webpack-config/package.json +++ b/packages/webpack-config/package.json @@ -22,7 +22,8 @@ "@ice/bundles": "^0.1.0", "@rollup/pluginutils": "^4.2.0", "consola": "^2.15.3", - "fast-glob": "^3.2.11" + "fast-glob": "^3.2.11", + "process": "^0.11.10" }, "devDependencies": { "esbuild": "^0.14.51", diff --git a/packages/webpack-config/src/index.ts b/packages/webpack-config/src/index.ts index 422fd2ecc..f2f119f76 100644 --- a/packages/webpack-config/src/index.ts +++ b/packages/webpack-config/src/index.ts @@ -280,6 +280,9 @@ const getWebpackConfig: GetWebpackConfig = ({ rootDir, config, webpack, runtimeT // use webpack-dev-server overlay instead overlay: false, }), + new webpack.ProvidePlugin({ + process: require.resolve('process/browser'), + }), new webpack.DefinePlugin({ ...defineVars, ...runtimeDefineVars, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8b6ce876d..1a9779e8d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1191,6 +1191,7 @@ importers: esbuild: ^0.14.51 fast-glob: ^3.2.11 postcss: ^8.4.18 + process: ^0.11.10 webpack: ^5.73.0 webpack-dev-server: ^4.7.4 dependencies: @@ -1202,6 +1203,7 @@ importers: '@swc/core': 1.3.3 consola: 2.15.3 fast-glob: 3.2.12 + process: 0.11.10 devDependencies: esbuild: 0.14.54 postcss: 8.4.18 @@ -15332,6 +15334,11 @@ packages: /process-nextick-args/2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + /process/0.11.10: + resolution: {integrity: sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==} + engines: {node: '>= 0.6.0'} + dev: false + /progress/2.0.3: resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} engines: {node: '>=0.4.0'}