Appearance
Webpack 入口与输出
Webpack 的入口(Entry)和输出(Output)配置决定了构建过程的起点和结果的存放位置。理解这些配置对于控制打包行为至关重要。
入口配置(Entry)
入口配置告诉 Webpack 从哪个模块开始构建依赖图。
单入口配置
javascript
// 单个入口文件
module.exports = {
entry: './src/index.js'
// 等价于
// entry: {
// main: './src/index.js'
// }
};
多入口配置
javascript
// 多个入口文件
module.exports = {
entry: {
home: './src/home.js',
about: './src/about.js',
contact: './src/contact.js'
},
output: {
filename: '[name].bundle.js', // [name] 对应入口键名
path: path.resolve(__dirname, 'dist')
}
};
高级入口配置
javascript
module.exports = {
entry: {
// 数组形式 - 多个文件作为一个入口
app: [
'./src/polyfills.js', // 垫片文件
'./src/index.js' // 主文件
],
// 对象形式 - 详细的入口配置
admin: {
import: './src/admin.js', // 入口文件
dependOn: 'shared', // 依赖于 shared chunk
filename: 'admin.bundle.js' // 自定义输出文件名
},
shared: {
import: ['./src/common.js', './src/utils.js'], // 多个入口文件
filename: 'shared.js'
}
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
输出配置(Output)
输出配置告诉 Webpack 如何输出编译后的文件。
基础输出配置
javascript
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js', // 输出文件名
path: path.resolve(__dirname, 'dist'), // 输出目录的绝对路径
publicPath: '/' // 公共路径
}
};
多入口输出配置
javascript
module.exports = {
entry: {
home: './src/home.js',
about: './src/about.js'
},
output: {
filename: '[name].[contenthash].js', // 使用内容哈希
path: path.resolve(__dirname, 'dist'),
publicPath: '/assets/' // 所有资源的基础路径
}
};
高级输出配置
javascript
module.exports = {
entry: {
app: './src/app.js',
vendor: './src/vendor.js'
},
output: {
filename: (pathData) => {
// 根据入口点动态生成文件名
return pathData.chunk.name === 'vendor'
? 'vendors.[contenthash].js'
: '[name].[contenthash].js';
},
chunkFilename: '[name].[contenthash].chunk.js', // 非入口 chunk 文件名
path: path.resolve(__dirname, 'dist'),
publicPath: process.env.NODE_ENV === 'production'
? 'https://cdn.example.com/'
: '/',
clean: true, // Webpack 5 - 构建前清理输出目录
assetModuleFilename: 'images/[hash][ext][query]' // 资源模块输出路径
}
};
公共路径配置(Public Path)
公共路径决定了构建后资源的引用路径。
静态公共路径
javascript
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/assets/' // 静态资源引用前缀
}
};
动态公共路径
javascript
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: (env) => {
// 根据环境变量动态设置公共路径
return env === 'production'
? 'https://cdn.example.com/'
: '/';
}
}
};
运行时公共路径
javascript
// 在应用代码中动态设置
__webpack_public_path__ = window.location.protocol + '//' + window.location.host + '/assets/';
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '' // 在代码中动态设置
}
};
代码分割与输出
使用 SplitChunksPlugin
javascript
module.exports = {
entry: {
home: './src/home.js',
about: './src/about.js'
},
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].chunk.js', // 分割后的 chunk 文件名
path: path.resolve(__dirname, 'dist')
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10,
chunks: 'all'
},
common: {
name: 'common',
minChunks: 2,
priority: 5,
chunks: 'all',
enforce: true
}
}
}
}
};
动态导入输出
javascript
// 在代码中使用动态导入
// src/index.js
import('./components/lazy-component')
.then(module => {
// 使用加载的模块
module.render();
});
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].[contenthash].js',
chunkFilename: 'chunks/[name].[contenthash].js', // 动态导入的 chunk 输出路径
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
}
};
环境特定配置
开发环境配置
javascript
// webpack.dev.js
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].js', // 不使用哈希,便于调试
path: path.resolve(__dirname, 'dist'),
publicPath: '/', // 开发服务器路径
clean: false // 不清理,保留缓存
}
};
生产环境配置
javascript
// webpack.prod.js
module.exports = {
entry: './src/index.js',
output: {
filename: '[name].[contenthash].js', // 使用内容哈希,更好的缓存
chunkFilename: '[name].[contenthash].chunk.js',
path: path.resolve(__dirname, 'dist'),
publicPath: 'https://cdn.example.com/', // CDN 路径
clean: true // 构建前清理输出目录
}
};
高级输出选项
非常数表达式
javascript
module.exports = {
entry: './src/index.js',
output: {
filename: ({ chunk }) => {
// 根据 chunk 名称生成不同的文件名
if (chunk.name === 'main') {
return 'main.[contenthash].js';
} else if (chunk.name.startsWith('page-')) {
return 'pages/[name].[contenthash].js';
}
return '[name].[contenthash].js';
},
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
}
};
跨平台路径处理
javascript
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
// 确保路径分隔符在不同操作系统上一致
pathinfo: true // 开发模式下保留路径信息
}
};
输出优化策略
缓存优化
javascript
module.exports = {
entry: {
app: './src/index.js'
},
output: {
filename: '[name].[contenthash].js', // 使用内容哈希实现长期缓存
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
clean: true
},
optimization: {
moduleIds: 'deterministic', // 确定性模块 ID
runtimeChunk: 'single', // 单独的运行时 chunk
splitChunks: {
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
chunks: 'all'
}
}
}
}
};
文件名优化
javascript
module.exports = {
entry: {
home: './src/home.js',
about: './src/about.js'
},
output: {
filename: (pathData) => {
// 根据路径数据生成有意义的文件名
const name = pathData.chunk.name;
if (name === 'runtime') {
return 'runtime.[contenthash].js';
} else if (name === 'vendors') {
return 'vendors.[contenthash].js';
} else {
return '[name].[contenthash].js';
}
},
chunkFilename: 'chunks/[name].[contenthash].chunk.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
}
};
小结
入口和输出配置是 Webpack 构建过程的基础,它们决定了构建的起点和结果的组织方式。通过合理的配置,我们可以实现代码分割、缓存优化、环境适配等功能。理解这些配置选项的含义和用法,对于构建高效的 Webpack 配置至关重要。