Create React App (CRA) 是 React 官方推荐的脚手架工具,它封装了 Webpack、Babel、ESLint 等工具,提供了开箱即用的开发环境。虽然 CRA 隐藏了大部分配置细节,但在某些情况下,我们可能需要自定义 Webpack 配置。本文将详细解读 CRA 的 Webpack 配置文件,帮助你理解其工作原理和核心配置。
1. 配置文件概览
我们先用create-react-app创建一个项目,然后npm run eject,可以看到webpack的配置文件
CRA 的 Webpack 配置它是一个函数,接收 webpackEnv 参数(表示当前环境,如 development 或 production),并返回一个 Webpack 配置对象。
配置文件的主要部分包括:
- 入口和输出配置
- 模块解析规则
- 插件配置
- 优化配置
- 开发和生产环境的差异处理
- 缓存配置
2. 核心配置解析
2.1 入口和输出配置
入口(Entry)
entry: paths.appIndexJs,
paths.appIndexJs是应用的入口文件,通常是src/index.js或src/index.tsx。
输出(Output)
output: {
path: paths.appBuild, // 构建输出目录
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js' // 生产环境使用哈希文件名
: isEnvDevelopment && 'static/js/bundle.js', // 开发环境使用固定文件名
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js' // 异步 chunk 文件名
: isEnvDevelopment && 'static/js/[name].chunk.js',
assetModuleFilename: 'static/media/[name].[hash][ext]', // 静态资源文件名
publicPath: paths.publicUrlOrPath, // 公共路径
}
path:构建输出的目录,通常是build。filename:主 bundle 的文件名,生产环境使用哈希值以支持缓存。chunkFilename:异步加载的 chunk 文件名。assetModuleFilename:静态资源(如图片、字体)的输出路径和文件名。publicPath:静态资源的公共路径,通常与homepage配置相关。
2.2 模块解析规则【loader】
模块解析(resolve)
源码如下:
resolve: {
modules: ['node_modules', paths.appNodeModules], // 模块查找路径
extensions: paths.moduleFileExtensions.map(ext => `.${ext}`), // 支持的扩展名
alias: {
'react-native': 'react-native-web', // 支持 React Native Web
...(modules.webpackAliases || {}), // 自定义别名
},
plugins: [
new ModuleScopePlugin(paths.appSrc, [ // 限制模块导入范围
paths.appPackageJson,
reactRefreshRuntimeEntry,
reactRefreshWebpackPluginRuntimeEntry,
babelRuntimeEntry,
babelRuntimeEntryHelpers,
babelRuntimeRegenerator,
]),
],
}
modules:模块查找路径,优先从node_modules和项目根目录的node_modules中查找。extensions:支持的扩展名,如.js、.jsx、.ts、.tsx。alias:路径别名,支持 React Native Web 和自定义别名。ModuleScopePlugin:限制模块导入范围,防止从src目录外导入模块。paths.appPackageJson:项目的package.json文件。reactRefreshRuntimeEntry:React 热更新的运行时入口文件。reactRefreshWebpackPluginRuntimeEntry:React 热更新插件的运行时入口文件。babelRuntimeEntry:Babel 运行时的入口文件。babelRuntimeEntryHelpers:Babel 运行时的辅助函数文件。babelRuntimeRegenerator:Babel 运行时的 regenerator 文件。
模块规则(Module Rules)
源码如下:
module: {
strictExportPresence: true,
rules: `[`
shouldUseSourceMap && {
enforce: 'pre',
exclude: /@babel(?:\/|\\{1,2})runtime/,
test: /\.(js|mjs|jsx|ts|tsx|css)$/,
loader: require.resolve('source-map-loader'),
},
{
oneOf: [
{
test: [/\.avif$/],
type: 'asset',
mimetype: 'image/avif',
parser: {
dataUrlCondition: {
maxSize: imageInlineSizeLimit,
},
},
},
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: imageInlineSizeLimit,
},
},
},
{
test: /\.svg$/,
use: [
{
loader: require.resolve('@svgr/webpack'),
options: {
prettier: false,
svgo: false,
svgoConfig: {
plugins: [{ removeViewBox: false }],
},
titleProp: true,
ref: true,
},
},
{
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash].[ext]',
},
},
],
issuer: {
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
},
},
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
customize: require.resolve(
'babel-preset-react-app/webpack-overrides'
),
presets: [
[
require.resolve('babel-preset-react-app'),
{
runtime: hasJsxRuntime ? 'automatic' : 'classic',
},
],
],
plugins: [
isEnvDevelopment &&
shouldUseReactRefresh &&
require.resolve('react-refresh/babel'),
[require.resolve('babel-plugin-transform-antd-resize-table'), { optionName: path.resolve(__dirname, '../src/components/table') }]
].filter(Boolean),
cacheDirectory: true,
cacheCompression: false,
compact: isEnvProduction,
},
},
{
test: /\.(js|mjs)$/,
exclude: /@babel(?:\/|\\{1,2})runtime/,
loader: require.resolve('babel-loader'),
options: {
babelrc: false,
configFile: false,
compact: false,
presets: [
[
require.resolve('babel-preset-react-app/dependencies'),
{ helpers: true },
],
],
cacheDirectory: true,
sourceMaps: shouldUseSourceMap,
inputSourceMap: shouldUseSourceMap,
},
},
{
test: cssRegex,
exclude: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
mode: 'icss',
},
}),
sideEffects: true,
},
{
test: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
mode: 'local',
getLocalIdent: getCSSModuleLocalIdent,
},
}),
},
{
test: sassRegex,
exclude: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
mode: 'icss',
},
},
'sass-loader'
),
sideEffects: true,
},
{
test: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
mode: 'local',
getLocalIdent: getCSSModuleLocalIdent,
},
},
'sass-loader'
),
},
{
exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
type: 'asset/resource',
},
],
},
].filter(Boolean),
},
module 是 Webpack 配置的核心部分,用于定义如何处理不同类型的文件(模块)。它包含两个主要属性:
strictExportPresence:设置为true,表示如果模块导出不存在,Webpack 会抛出错误。rules:定义了一系列规则(rules),每个规则指定了如何处理特定类型的文件。
接下来一个一个分析其作用
处理 Source Maps
shouldUseSourceMap && {
enforce: 'pre',
exclude: /@babel(?:\/|\\{1,2})runtime/,
test: /\.(js|mjs|jsx|ts|tsx|css)$/,
loader: require.resolve('source-map-loader'),
}
- 作用:在开发环境中,使用
source-map-loader加载 Source Maps,以便在调试时能够定位到源代码。 enforce: 'pre':确保该 loader 在其他 loader 之前执行。exclude:排除@babel/runtime中的文件,避免重复处理。test:匹配 JavaScript、TypeScript 和 CSS 文件。
oneOf 规则
oneOf 是 Webpack 的一种优化机制,它会按顺序遍历规则列表,直到找到匹配的规则。如果没有匹配的规则,则使用最后的 file-loader。
处理 AVIF 图片
{
test: [/\.avif$/],
type: 'asset',
mimetype: 'image/avif',
parser: {
dataUrlCondition: {
maxSize: imageInlineSizeLimit,
},
},
}
- 作用:处理 AVIF 格式的图片。
type: 'asset':将文件作为资源处理,小于imageInlineSizeLimit的图片会转为 Base64 编码。mimetype:指定文件的 MIME 类型。
处理常见图片格式
{
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
type: 'asset',
parser: {
dataUrlCondition: {
maxSize: imageInlineSizeLimit,
},
},
}
- 作用:处理 BMP、GIF、JPEG、PNG 等常见图片格式。
type: 'asset':将文件作为资源处理,小于imageInlineSizeLimit的图片会转为 Base64 编码。
处理 SVG 图片
{
test: /\.svg$/,
use: [
{
loader: require.resolve('@svgr/webpack'),
options: {
prettier: false,
svgo: false,
svgoConfig: {
plugins: [{ removeViewBox: false }],
},
titleProp: true,
ref: true,
},
},
{
loader: require.resolve('file-loader'),
options: {
name: 'static/media/[name].[hash].[ext]',
},
},
],
issuer: {
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
},
}
- 作用:处理 SVG 图片,并使用
@svgr/webpack将其转换为 React 组件。 @svgr/webpack:将 SVG 文件转换为 React 组件。file-loader:处理 SVG 文件的静态资源路径。
处理应用代码(JavaScript/TypeScript)
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
include: paths.appSrc,
loader: require.resolve('babel-loader'),
options: {
customize: require.resolve('babel-preset-react-app/webpack-overrides'),
presets: [
[
require.resolve('babel-preset-react-app'),
{
runtime: hasJsxRuntime ? 'automatic' : 'classic',
},
],
],
plugins: [
isEnvDevelopment &&
shouldUseReactRefresh &&
require.resolve('react-refresh/babel'),
[require.resolve('babel-plugin-transform-antd-resize-table'), { optionName: path.resolve(__dirname, '../src/components/table') }]
].filter(Boolean),
cacheDirectory: true,
cacheCompression: false,
compact: isEnvProduction,
},
}
- 作用:使用 Babel 编译应用代码(JavaScript 和 TypeScript)。
include:仅处理src/目录下的文件。babel-loader:使用 Babel 编译代码。presets:使用babel-preset-react-app预设,支持 React 和 TypeScript。plugins:react-refresh/babel:在开发环境中启用 React 热更新。babel-plugin-transform-antd-resize-table:自定义插件,用于处理 Ant Design 表格组件的调整大小功能。
cacheDirectory:启用 Babel 缓存,加快构建速度。
处理第三方库代码
{
test: /\.(js|mjs)$/,
exclude: /@babel(?:\/|\\{1,2})runtime/,
loader: require.resolve('babel-loader'),
options: {
babelrc: false,
configFile: false,
compact: false,
presets: [
[
require.resolve('babel-preset-react-app/dependencies'),
{ helpers: true },
],
],
cacheDirectory: true,
cacheCompression: false,
sourceMaps: shouldUseSourceMap,
inputSourceMap: shouldUseSourceMap,
},
}
- 作用:使用 Babel 编译第三方库代码。
exclude:排除@babel/runtime中的文件。presets:使用babel-preset-react-app/dependencies预设,仅编译标准的 ES 特性。
处理 CSS 文件
{
test: cssRegex,
exclude: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
modules: {
mode: 'icss',
},
}),
sideEffects: true,
}
- 作用:处理普通的 CSS 文件。
getStyleLoaders:返回一组 loader,包括style-loader、css-loader和postcss-loader。modules.mode: 'icss':启用 ICSS(Interoperable CSS)模式。
处理 CSS Modules
{
test: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
modules: {
mode: 'local',
getLocalIdent: getCSSModuleLocalIdent, // 使用 CRA 的类名生成规则
},
}),
}
- 作用:处理 CSS Modules 文件。
modules.mode: 'local':启用 CSS Modules 的局部作用域。getLocalIdent: 使用 CRA 的类名生成规则
处理 Sass 文件
{
test: sassRegex,
exclude: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
modules: {
mode: 'icss',
},
},
'sass-loader'
),
sideEffects: true,
}
- 作用:处理普通的 Sass 文件。
sass-loader:将 Sass 编译为 CSS。
处理 Sass Modules
{
test: sassModuleRegex,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
modules: {
mode: 'local',
getLocalIdent: getCSSModuleLocalIdent,
},
},
'sass-loader'
),
}
- 作用:处理 Sass Modules 文件。
modules.mode: 'local':启用 CSS Modules 的局部作用域。
处理其他文件
{
exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],
type: 'asset/resource',
}
- 作用:处理其他类型的文件(如图片、字体等)。
type: 'asset/resource':将文件作为静态资源处理,并输出到指定目录。
2.3 插件配置【plugin】
源码如下:
plugins: [
new HtmlWebpackPlugin({ // 生成 HTML 文件
inject: true,
template: paths.appHtml,
minify: isEnvProduction ? { // 生产环境压缩 HTML
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
} : undefined,
}),
isEnvProduction &&
new MiniCssExtractPlugin({ // 提取 CSS 文件
filename: 'static/css/[name].[contenthash:8].css',
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
}),
new webpack.DefinePlugin(env.stringified), // 注入环境变量
isEnvDevelopment &&
shouldUseReactRefresh &&
new ReactRefreshWebpackPlugin({ // 支持 React 热更新
overlay: false,
}),
isEnvProduction &&
new WorkboxWebpackPlugin.InjectManifest({ // 生成 Service Worker
swSrc,
dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
}),
useTypeScript &&
new ForkTsCheckerWebpackPlugin({ // TypeScript 类型检查
async: isEnvDevelopment,
typescript: {
typescriptPath: resolve.sync('typescript', {
basedir: paths.appNodeModules,
}),
configOverwrite: {
compilerOptions: {
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
skipLibCheck: true,
incremental: true,
tsBuildInfoFile: paths.appTsBuildInfoFile,
},
},
},
}),
!disableESLintPlugin &&
new ESLintPlugin({ // ESLint 检查
extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
formatter: require.resolve('react-dev-utils/eslintFormatter'),
eslintPath: require.resolve('eslint'),
failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),
context: paths.appSrc,
cache: true,
}),
].filter(Boolean);
HtmlWebpackPlugin
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: paths.appHtml,
},
isEnvProduction
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined
)
)
- 作用:生成
index.html文件,并自动注入打包后的 JavaScript 和 CSS 文件。 - 配置:
inject: true:自动将生成的资源文件注入到 HTML 中。template: paths.appHtml:使用指定的 HTML 模板文件(通常是public/index.html)。minify:在生产环境中启用 HTML 压缩,移除注释、空白字符等。
InlineChunkHtmlPlugin
isEnvProduction &&
shouldInlineRuntimeChunk &&
new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/])
- 作用:将 Webpack 的 runtime 代码内联到 HTML 中,减少网络请求。
- 条件:仅在生产环境且
shouldInlineRuntimeChunk为true时启用。 - 参数:
HtmlWebpackPlugin:指定要操作的 HTML 插件。[/runtime-.+[.]js/]:匹配需要内联的 runtime 文件。
InterpolateHtmlPlugin
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw)
- 作用:在 HTML 中插入环境变量。例如,
%PUBLIC_URL%会被替换为publicUrlOrPath。 - 参数:
HtmlWebpackPlugin:指定要操作的 HTML 插件。env.raw:环境变量对象。
ModuleNotFoundPlugin
new ModuleNotFoundPlugin(paths.appPath)
- 作用:在模块未找到时提供更友好的错误提示,帮助开发者快速定位问题。
- 参数:
paths.appPath:项目的根目录。
DefinePlugin
new webpack.DefinePlugin(env.stringified)
- 作用:在编译时将环境变量注入到代码中。例如,
process.env.NODE_ENV会被替换为"production"或"development"。 - 参数:
env.stringified:环境变量对象,键值对会被注入到代码中。
ReactRefreshWebpackPlugin
isEnvDevelopment &&
shouldUseReactRefresh &&
new ReactRefreshWebpackPlugin({
overlay: false,
})
- 作用:在开发环境中启用 React 组件的热更新(Hot Module Replacement, HMR)。
- 条件:仅在开发环境且
shouldUseReactRefresh为true时启用。 - 参数:
overlay: false:禁用错误覆盖层。
CaseSensitivePathsPlugin
isEnvDevelopment && new CaseSensitivePathsPlugin()
- 作用:在开发环境中检查文件路径的大小写敏感性,避免因路径大小写不一致导致的错误。
- 条件:仅在开发环境中启用。
MiniCssExtractPlugin
isEnvProduction &&
new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash:8].css',
chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',
})
- 作用:将 CSS 提取为单独的文件,而不是内联到 JavaScript 中。
- 条件:仅在生产环境中启用。
- 参数:
filename:主 CSS 文件的输出路径和名称。chunkFilename:异步加载的 CSS 文件的输出路径和名称。
WebpackManifestPlugin
new WebpackManifestPlugin({
fileName: 'asset-manifest.json',
publicPath: paths.publicUrlOrPath,
generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => {
manifest[file.name] = file.path;
return manifest;
}, seed);
const entrypointFiles = entrypoints.main.filter(
fileName => !fileName.endsWith('.map')
);
return {
files: manifestFiles,
entrypoints: entrypointFiles,
};
},
})
- 作用:生成资源清单文件(
asset-manifest.json),记录所有打包后的资源文件及其路径。 - 参数:
fileName:清单文件的名称。publicPath:资源的公共路径。generate:自定义清单文件的生成逻辑。
IgnorePlugin
new webpack.IgnorePlugin({
resourceRegExp: /^\.\/locale$/,
contextRegExp: /moment$/,
})
- 作用:忽略
moment.js中的本地化文件,减少打包体积。 - 参数:
resourceRegExp:匹配要忽略的资源。contextRegExp:匹配资源的上下文。
WorkboxWebpackPlugin.InjectManifest
isEnvProduction &&
fs.existsSync(swSrc) &&
new WorkboxWebpackPlugin.InjectManifest({
swSrc,
dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,
exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
})
- 作用:生成 Service Worker 文件,支持 PWA(渐进式 Web 应用)。
- 条件:仅在生产环境且
swSrc文件存在时启用。 - 参数:
swSrc:Service Worker 的源文件路径。dontCacheBustURLsMatching:匹配不需要缓存的文件。exclude:排除不需要缓存的文件。maximumFileSizeToCacheInBytes:设置缓存文件的最大大小。
ForkTsCheckerWebpackPlugin
useTypeScript &&
new ForkTsCheckerWebpackPlugin({
async: isEnvDevelopment,
typescript: {
typescriptPath: resolve.sync('typescript', {
basedir: paths.appNodeModules,
}),
configOverwrite: {
compilerOptions: {
sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,
skipLibCheck: true,
inlineSourceMap: false,
declarationMap: false,
noEmit: true,
incremental: true,
tsBuildInfoFile: paths.appTsBuildInfoFile,
},
},
context: paths.appPath,
diagnosticOptions: {
syntactic: true,
},
mode: 'write-references',
},
issue: {
include: [
{ file: '../**/src/**/*.{ts,tsx}' },
{ file: '**/src/**/*.{ts,tsx}' },
],
exclude: [
{ file: '**/src/**/__tests__/**' },
{ file: '**/src/**/?(*.){spec|test}.*' },
{ file: '**/src/setupProxy.*' },
{ file: '**/src/setupTests.*' },
],
},
logger: {
infrastructure: 'silent',
},
})
- 作用:在单独的进程中检查 TypeScript 类型错误,提升构建速度。
- 条件:仅在项目使用 TypeScript 时启用。
- 参数:
async: isEnvDevelopment:在开发环境中异步检查类型错误。typescript:TypeScript 配置,包括路径、编译器选项等。issue:指定需要检查的文件范围。logger:控制日志输出。
ESLintPlugin
!disableESLintPlugin &&
new ESLintPlugin({
extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
formatter: require.resolve('react-dev-utils/eslintFormatter'),
eslintPath: require.resolve('eslint'),
failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),
context: paths.appSrc,
cache: true,
cacheLocation: path.resolve(
paths.appNodeModules,
'.cache/.eslintcache'
),
cwd: paths.appPath,
resolvePluginsRelativeTo: __dirname,
baseConfig: {
extends: [require.resolve('eslint-config-react-app/base')],
rules: {
...(!hasJsxRuntime && {
'react/react-in-jsx-scope': 'error',
}),
},
},
})
- 作用:在 Webpack 构建过程中运行 ESLint,检查代码规范。
- 条件:仅在未禁用 ESLint 时启用。
- 参数:
extensions:需要检查的文件扩展名。formatter:指定 ESLint 的输出格式。failOnError:在发现错误时是否终止构建。context:指定 ESLint 的工作目录。cache:启用 ESLint 缓存,提升检查速度。baseConfig:指定 ESLint 的基础配置。
2.4 优化配置
代码压缩
optimization: {
minimize: isEnvProduction,
minimizer: [
new TerserPlugin({ // 压缩 JavaScript
terserOptions: {
parse: { ecma: 8 },
compress: { ecma: 5, warnings: false, comparisons: false, inline: 2 },
mangle: { safari10: true },
output: { ecma: 5, comments: false, ascii_only: true },
},
}),
new CssMinimizerPlugin(), // 压缩 CSS
],
}
TerserPlugin:压缩 JavaScript 代码。CssMinimizerPlugin:压缩 CSS 代码。
代码分割
splitChunks: {
chunks: 'all', // 对所有 chunk 进行代码分割
name: false, // 不指定 chunk 名称
},
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`, // 提取 runtime 代码
},
splitChunks:将公共代码提取到单独的 chunk 中。runtimeChunk:提取 Webpack 的 runtime 代码,减少重复加载。
2.5 缓存配置
cache: {
type: 'filesystem',
version: createEnvironmentHash(env.raw),
cacheDirectory: paths.appWebpackCache,
store: 'pack',
buildDependencies: {
defaultWebpack: ['webpack/lib/'],
config: [__filename],
tsconfig: [paths.appTsConfig, paths.appJsConfig].filter(f =>
fs.existsSync(f)
),
},
},
缓存的作用
Webpack 的缓存机制可以显著提升构建性能,尤其是在大型项目中。它的核心作用包括:
- 减少重复编译:通过缓存已编译的模块,避免重复处理未变化的文件。
- 加快构建速度:在后续构建中直接使用缓存结果,减少构建时间。
- 支持增量构建:只重新编译变化的文件,而不是整个项目。
配置详解
type: 'filesystem'
type: 'filesystem'
- 作用:启用文件系统缓存,将缓存数据存储到磁盘中。
- 说明:
- Webpack 5 引入了持久化缓存功能,支持将缓存数据存储到文件系统中。
- 与内存缓存(
memory)相比,文件系统缓存在重启构建后仍然有效。
version: createEnvironmentHash(env.raw)
version: createEnvironmentHash(env.raw)
- 作用:为缓存生成一个唯一的版本标识符。
- 说明:
createEnvironmentHash是一个工具函数,用于根据环境变量(env.raw)生成哈希值。- 当环境变量发生变化时,缓存版本会更新,确保缓存数据的有效性。
cacheDirectory: paths.appWebpackCache
cacheDirectory: paths.appWebpackCache
- 作用:指定缓存文件的存储目录。
- 说明:
paths.appWebpackCache是缓存目录的路径,通常是node_modules/.cache/webpack。- 缓存文件会存储在该目录下,以便后续构建时复用。
store: 'pack'
store: 'pack'
- 作用:指定缓存存储的方式。
- 说明:
pack是 Webpack 5 中的一种缓存存储方式,它会将缓存数据打包成一个文件。- 这种方式可以减少文件数量,提升缓存读写效率。
buildDependencies
buildDependencies: {
defaultWebpack: ['webpack/lib/'],
config: [__filename],
tsconfig: [paths.appTsConfig, paths.appJsConfig].filter(f =>
fs.existsSync(f)
),
}
- 作用:指定构建依赖,当这些依赖发生变化时,缓存会失效。
- 说明:
defaultWebpack: ['webpack/lib/']:将 Webpack 的核心库作为构建依赖。如果 Webpack 版本发生变化,缓存会失效。config: [__filename]:将当前配置文件(webpack.config.js)作为构建依赖。如果配置文件发生变化,缓存会失效。tsconfig: [paths.appTsConfig, paths.appJsConfig]:将 TypeScript 配置文件(tsconfig.json)和 JavaScript 配置文件(jsconfig.json)作为构建依赖。如果这些文件发生变化,缓存会失效。