免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

深入解读 @ice/shared-config:ice.js 中 rspack 与 webpack 共享编译配置包的架构演进

深入解读 @ice/shared-config:ice.js 中 rspack 与 webpack 共享编译配置包的架构演进 前端Web框架SSR前端构建插件系统微前端跨平台【免费下载链接】ice ice.js: The Progressive App Framework Based On React基于 React 的渐进式应用框架项目地址https://gitcode.com/gh_mirrors/ice1/ice点击查看免费下载导读ice/shared-config是 ice.js 框架中面向 rspack 与 webpack 双编译器提供统一共享配置的编译内核包本篇文章以该包的 CHANGELOG.md 为演进主线结合 src 目录 下的真实实现与 tests 目录 的测试用例逐版本解析其从 SWC 编译管线、插件编排、导入重定向到构建变量注入的完整设计帮助读者既掌握该包的全部配置能力也理解 ice.js 构建层的关键原理。一、包定位一个包统一两套编译器的共享配置ice/shared-config当前版本 1.3.2见 package.json在仓库中的官方定位非常精炼This package providers shared configuration for rspack and webpack.—— 它为 ice.js 构建链中的rspack与webpack两套打包器提供同一份共享配置逻辑避免双编译器环境下配置代码双写与行为漂移。该包本身的构建产物是一个 ESM 模块type: modulemain指向./esm/index.js并在exports中暴露了三个入口.→./esm/index.js主入口导出全部配置生成函数./compilation-loader→./esm/webpackLoaders/compilationLoader.cjswebpack 模式下使用的编译 loader./types→./esm/types.js构建配置的 TypeScript 类型定义。从依赖关系看它不直接依赖原生 webpack而是统一从ice/bundles当前为 0.2.9获取编译过的 webpack、SWC、postcss、lodash、unplugin 等依赖——这正是 CHANGELOG 1.3.1 中 use ice/bundles instead of import webpack directly 的落地成果目的是锁定依赖版本、保证多包行为一致。主入口 index.ts 集中导出了 12 个能力单元构成该包的完整 API 面导出项职责compilationPlugin基于 SWC 的源码编译 unpluginJSX/TSX 转换、polyfill、导出处理getJsxTransformOptions生成 SWC 的 JSX/TSX 转换配置getSupportedBrowsers/isSupportedFeature基于 browserslist 的目标浏览器探测与特性支持判断compileExcludes/skipCompilePackages编译排除规则与跳过编译的包名列表getCompilerPlugins按编译器webpack/rspack/esbuild编排 unplugin 顺序getDefineVars构建期全局变量process.env.*、import.meta.env注入getPostcssOptsPostCSS 配置生成与合并getCSSModuleLocalIdentCSS Modules 类名生成含纯 hash 模式getAliasWithRoot别名alias解析与根目录补全getDevtoolValuesourcemap devtool 取值归一化下文将围绕这些能力逐层展开并在对应小节回扣 CHANGELOG 中的演进记录。二、编译管线基于 SWC 的 compilationPlugin2.1 从“代码转换器”到“统一编译内核”compilationPlugin实现在 unPlugins/compilation.ts是该包最核心的模块它本质上是一个 unplugin可同时运行于 webpack/rspack负责把项目源码中的 JSX/TSX 等现代语法通过SWC转换为可打包代码并在此过程中完成 polyfill 注入、导出裁剪、node 端转换等 ice.js 特有的语义处理。其入口配置项如下对应源码中的Options接口interface Options { rootDir: string; mode: development | production | none; fastRefresh: boolean; compileIncludes?: (string | RegExp)[]; sourceMap?: Config[sourceMap]; compileExcludes?: RegExp[]; swcOptions?: Config[swcOptions]; cacheDir?: string; polyfill?: Config[polyfill]; enableEnv?: boolean; getRoutesFile?: () string[]; }transformInclude决定了哪些文件进入编译匹配.jsx?/tsx?/mjs后缀且不被compileExcludes命中同时node_modules下的依赖默认跳过除非命中了compileIncludes或内置的COMPILE_DEPS目前内置了remix-run/router源码注释说明这是为规避 SWC minify 对该库编译时的挂起问题。2.2 默认关闭 swcrc1.2.2 的确定性编译CHANGELOG 1.2.2 记录了一条重要修复fix: disable swcrc by default。在 compilation.ts 中可以看到编译选项始终以swcrc: false起步const programmaticOptions: SwcConfig { swcrc: false, filename: id, sourceMaps: !!sourceMap, };这意味着 ice.js 的编译行为完全由程序化传入的选项决定不受项目根目录swcrc文件干扰从而保证同一次构建在不同机器、不同仓库下行为一致——这是框架级构建工具保证“确定性输出”的典型做法。2.3 JSX 转换选项importSource与 helpers 外置getJsxTransformOptionscompilation.ts生成 SWC 的 JSX 转换配置const reactTransformConfig: ReactConfig { development: mode development, refresh: fastRefresh, runtime: automatic, importSource: ice/runtime/react, // The exact import source is ice/runtime/react/jsx-runtime };runtime: automatic采用 React 17 的自动 JSX runtime源码中无需显式import ReactimportSource: ice/runtime/react把 JSX runtime 重定向到 ice.js 自己的 runtime 包即 CHANGELOG 1.1.0 modify import source 所做的事使 JSX 转换产物与框架 runtime 深度绑定externalHelpers: true开启swc/helpers外置注释明确指出“This option will greatly reduce your file size while bundling”配合按需 import 重写降低产物体积默认编译目标当enableEnv为 false 时设jsc.target es2022当开启enableEnv时则走 browserslist 目标见下。development标志还会在模式为 development 时自动补全源码第 89-95 行保证 fast refresh 等开发期能力正确启用。2.4 浏览器目标与 polyfillbrowserslist 与 core-jsenableEnv开启后编译选项会附加commonOptions.env { loose: false, ...(polyfill ? { mode: polyfill, // usage | entry | false coreJs: 3.32, } : {}), };其中mode对应 types.ts 中polyfill?: usage | entry | false的定义与 Babel 的 polyfill 模式语义一致。目标浏览器通过getSupportedBrowsers(rootDir, isDevelopment)compilation.ts读取项目根目录的 browserslist 配置browsers browserslist.loadConfig({ path: dir, env: isDevelopment ? development : production, });它支持按 development/production 环境分别取不同的 browserslist 目标。isSupportedFeature则进一步借助ice/bundles内置的 caniuse-lite 数据判断某个浏览器特性在当前目标浏览器集合中是否被支持——这是框架实现“特性降级/特性探测”的基础设施。演进佐证CHANGELOG 1.2.9 fix: mark browserslist config to cache key 表明 browserslist 配置已被纳入编译缓存键cache key即 browserslist 配置变化会正确触发缓存失效避免开发者修改浏览器目标后仍命中旧编译缓存。2.5 导出裁剪与 Node 端转换swcOptions 的四种能力swcOptions定义于 types.ts支持四种编译期语义操作全部通过 SWC experimental plugins 注入removeExportExprs对src/app.tsx与路由页面入口移除指定的导出表达式如definePageConfig防止页面配置对象被错误打进运行时 bundlekeepExports保留指定导出如pageConfig、default源码中专门处理了“构建 pageConfig 时同时保留 default等价于 getAppConfig”的细节并支持{ value: string[]; include?: (id) boolean }形式做自定义匹配nodeTransform针对服务端/Node 环境的转换compilationConfig最灵活的选项——CHANGELOG1.2.7 feat: support options for compilationConfig使其支持两种形态compilationConfig?: SwcCompilationConfig | ((source: string, id: string, options: GetJsxTransformOptions) SwcCompilationConfig);既可以传静态配置对象也可以传函数按(源码, 文件路径, 编译选项)动态返回配置最终通过 lodashmerge深度合并进 SWC 的程序化选项。判定目标文件是否属于路由入口或 app 入口时isRouteEntry依赖getRoutesFile()回调拿到路由文件列表isAppEntry则用正则匹配src/app.(ts|tsx|js|jsx)。这也解释了 CHANGELOG1.2.6 refactor: the compilation for>export const SKIP_COMPILE [ // polyfill and helpers core-js, core-js-pure, swc/helpers, babel/runtime, tslib, // Deprecate version of babel/runtime. babel-runtime, // built-in runtime react, react-dom, // dev dependencies pmmmwh/react-refresh-webpack-plugin, webpack, webpack-dev-server, react-refresh, ]; const compileExcludes [ new RegExp(SKIP_COMPILE.map((dep) node_modules/[\\w-\\.]*${dep}/).join(|)), /ice\/bundles\/compiled/, ];所有 polyfill/helperscore-js、swc/helpers、babel/runtime、tslibReact 运行时本体react、react-dom开发期依赖react-refresh 系列、webpack 系列以及ice/bundles/compiled下已编译的依赖——这些产物不再二次编译直接作为预编译代码使用。3.2 插件顺序enforce pre/post 与 rspack 反序getCompilerPlugins.ts 负责按编译器类型把上述 unplugin 组织为最终插件列表其顺序设计是理解该包的关键自定义 transformpretransformPlugins中enforce为pre或无值者、以及transforms数组中的自定义转换器最先执行——注释说明这样安排是为了“在 SWC 编译之前拿到原始源码”compilationPlugin仅对非 webpack/rspack 的编译器如 esbuild以 unplugin 形式注入对于 webpack/rspack 这类客户端打包器改用 webpack loader 而非 plugin 执行编译源码注释明确给出了原因unplugin 的 issue #154loader 方式可规避 webpack 中的钩子顺序问题自定义 transformpostenforce: post的转换器在 SWC 之后执行redirectImportPlugin最后追加导入重定向插件见第四节。细节上有两点值得注意一是 webpack/rspack 模式下所有插件会被createUnplugin(...)[compiler]()包装成对应编译器的原生插件二是rspack 模式下会将最终插件列表reverse()注释说明 unplugin 在 rspack 中的执行顺序发生了反转以保证两套编译器下的执行顺序完全一致。演进佐证1.1.2 fix: reorder transform plugins 正是对上述排序逻辑的修正1.1.1 feat: support custom transform plugins in speedup mode 对应transformPlugins配置的引入1.1.0 fix: compatible with configureWebpack in speedup mode 则对应 types.ts 中configureWebpack?: ModifyWebpackConfig[]配置在多编译器模式下的兼容处理。3.3 webpack 编译 loadercompilationLoader.cts对于 webpack 模式包通过exports[./compilation-loader]单独暴露了 webpackLoaders/compilationLoader.cts。这是一个标准的异步 loader从this.getOptions()读取transform函数调用transform(source, this.resourcePath)得到{ code, map }后经this.async()回调返回错误则交给 webpack 错误管线处理。它把编译逻辑与 webpack loader 机制解耦任何希望复用该编译能力的 webpack 配置都可以直接挂载此 loader。四、导入重定向redirectImport 与 definePageConfig 的按需分发4.1 为什么需要重定向ice.js 采用“统一入口导出、按需重定向”的 API 设计用户代码统一import { runApp, definePageConfig, ... } from ice但实际实现分散在各个 runtime 包中。redirectImportPlugin实现在 unPlugins/redirectImport.ts在编译期把这些具名导入精确拆解并重定向到各自的真实实现源。配置入口是Config.redirectImportstypes.tsinterface ImportDeclaration { specifier?: string | string[]; source: string; type?: boolean; alias?: Recordstring, string; }例如把definePageConfig从ice重定向到ice/runtime的对应实现——这正是 CHANGELOG1.0.3 fix: redirect import of definePageConfig所引入/修复的能力。4.2 实现要点lexer 解析 MagicString 改写redirectImport的核心流程用es-module-lexer解析出所有 import 声明仅处理targetSource固定为ice的导入用正则拆解{ A, B as C, ... }形式的具名导入支持as本地别名AS_ALIAS_REG_EXP命中的标识符按配置生成新的 import 语句generateImport未命中的标识符保留在原 import 中实现“部分重定向、部分保留”通过MagicString.overwrite精准替换原始 import 区间支持 sourcemap 生成hires: true。该插件默认只处理**/*.{ts,js,tsx,jsx}且排除node_modules/**对应的测试覆盖在 tests/redirectImport.test.ts其 fixturestests/fixtures/redirectImport包含basic.js、as.js、alias.js、multiple.js、matched.js、missmatch.js等场景逐一验证默认导入、as别名、自定义别名、多标识符混合、部分命中/未命中时的改写行为。五、构建变量、PostCSS 与 CSS Modules5.1 构建期变量注入getDefineVarsgetDefineVars.ts 负责把环境变量注入为构建期常量规则如下ICE_前缀环境变量 NODE_ENV自动注入为process.env.KEY形式的替换常量其中ICE_CORE_*前缀变量在 webpack 下使用DefinePlugin.runtimeValue(..., true)动态求值注释说明这类变量会被动态更新因此需要运行时取值而非静态字符串import.meta.env注入用户自定义的 env 变量集合形如import.meta.env.KEY强约束返回对象强制将process.env.ICE_CORE_SSR与process.env.ICE_CORE_SSG置为false——注释明确说明这是保证“CSR 模式下 SSR/SSG 开关恒为 false”的兜底约束。5.2 Provide 插件 definitions1.3.1 的新增能力CHANGELOG1.3.1 feat: support pass definitions for provide plugin对应 types.ts 中新增的配置项definitions?: Recordstring, string | string[];它允许调用方把全局标识符如process.env.XXX或React之类的全局快捷名以 definitions 形式透传给 webpack 的 ProvidePlugin 等插件在编译期完成全局符号的自动注入。5.3 PostCSS 配置生成getPostcssOptsgetPostcssOpts.ts 的决策逻辑非常清晰若项目根目录存在postcss.config.js则完全信任用户配置仅注入锁版本的implementation: postcss来自ice/bundles否则使用内置默认插件链postcss-nestedpostcss-preset-envstage: 3即启用 Stage 3 特性autoprefixer.flexbox: no-2009禁用旧版 flexbox 前缀关闭custom-properties小程序场景下enableRpx2Vw为 true追加postcss-plugin-rpx2vw实现 rpx → vw 的转换用户传入的postcssOptions通过 lodashmergeWith与默认配置合并数组字段采用 concat 策略。5.4 CSS Modules 类名hash-only 模式1.0.4getCSSModuleLocalIdent.ts 实现 CSS Modules 的类名生成配置了localIdentName如 webpack 风格模板时交给ice/bundles内置的 Rust 实现getCssModulesLocalIdent生成未配置时走内置 hash-only 逻辑对filename localName做 MD5取 base64 摘要并剔除前导数字、斜杠与非字母数字下划线字符截取前 8 位最终形如localName--AbCd1234。这正是 CHANGELOG1.0.4 feat: support hash only class name for css modules描述的能力在不配置模板时类名只保留“本地名 纯 hash 后缀”体积更小且不易冲突。六、别名解析与 sourcemap 归一化getAliasWithRootgetAlias.ts把配置中以.开头的相对路径别名自动拼接到rootDir下保证别名在任何工作目录下都指向项目根避免别名解析漂移getDevtoolValueutils/getDevtool.ts对sourceMap配置做归一化——字符串原样透传、false返回false、其余undefined/true返回source-map统一 webpack/rspack 的 devtool 取值语义。演进佐证CHANGELOG 1.2.5 fix: improve dev sourcemap 正是围绕 devtool 取值与 sourcemap 产出的优化而 1.0.3 fix: sourceMap url in prod files but not publish with sourceMap file 则修复了生产构建产物中 sourceMapURL 指向但未随包发布 sourcemap 文件的不一致问题。七、版本演进全览从 1.0.1 到 1.3.2CHANGELOG 记录了该包从 1.0.1 到 1.3.2 共 15 个发布版本的完整演进。按主题可划分为四个阶段阶段一1.0.x基础能力构建期版本类型变更1.0.1Patch首个可发布版本随ice/bundles0.1.14发布1.0.2Patchfix: 转换含特殊标识符的 importimport.meta等场景1.0.3Patchfix: 生产产物 sourceMap URL 与 sourcemap 文件发布不一致fix: 重定向definePageConfig的导入1.0.4Patchfeat: 支持 CSS Modules 纯 hash 类名这一阶段确立了包的三块基石SWC 编译管线、transformImport产物改写、redirectImport导入重定向。阶段二1.1.x插件编排与 speedup 兼容期版本类型变更1.1.0Minorfix: 修改 JSX runtime 的 import 来源ice/runtime/reactfix: speedup 模式下兼容configureWebpack1.1.1Patchfix: speedup 模式支持自定义 transform 插件升级ice/bundles0.1.171.1.2Patchfix: 重排 transform 插件执行顺序该阶段围绕“多编译器一致性”展开通过transformPlugins的enforce: pre/post语义与顺序调整让自定义转换器在 webpack/rspack/esbuild 三种编译器下都能获得确定性执行顺序。阶段三1.2.xpack-binding 与编译体验优化期版本类型变更1.2.0Minorfeat: 支持ice/pack-bindingfix: 优化 utils升级ice/bundles0.2.01.2.1Patch升级ice/bundles0.2.11.2.2Patchfix: 默认禁用 swcrcfeat: 支持优化包导入optimizePackageImports见 types.ts1.2.3Patch升级ice/bundles0.2.31.2.4Patch升级ice/bundles0.2.41.2.5Patchfix: 对齐 webpack 模式下的转换顺序与内容fix: 优化开发期 sourcemap1.2.6Patchrefactor: 重构>赞分享前端Web框架SSR前端构建插件系统微前端跨平台【免费下载链接】ice ice.js: The Progressive App Framework Based On React基于 React 的渐进式应用框架项目地址https://gitcode.com/gh_mirrors/ice1/ice点击查看免费下载相关推荐深入解析 ice/webpack-configice.js 应用框架的 Webpack 配置引擎深入解析 ice/webpack configice.js 应用框架的 Webpack 配置引擎 导读 ice/webpack config 是 ice.前端Web框架SSR前端构建插件系统微前端跨平台深入 Lucide 内部解读 lucide/shared 共享工具包的设计与源码实现深入 Lucide 内部解读 lucide/shared 共享工具包的设计与源码实现 导读 lucide/shared 是 Lucide 图标工具链中一个前端UI组件设计系统深入解析 marimo-team/tsconfigmarimo 前端共享 TypeScript 编译配置包的设计与实践深入解析 marimo team/tsconfigmarimo 前端共享 TypeScript 编译配置包的设计与实践 marimo team/tscon数据科学前端后端AI 应用上一篇Buzz信息架构组织平台内容的最佳实践下一篇Naive UI 树型选择组件 TreeSelect 完整实战指南Props、勾选策略、异步加载与源码解析创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表