关于 webpack 相关的文章太多了,何不一起从零开始手写一个配置呢?
真的3秒能打包一个three.js项目吗?真的,后面会提供源文件地址哦。
要打包的项目是这个样子的。
从零开始
关于 three.js
的安装和使用部分都省略。
首先是最基础的。我们需要安装
cross-env
目前最流行的运行跨平台设置和使用环境变量的脚本webpack
+webpack-cli
+webpack-dev-server
:三'贱'客,项目必备
参考常规webpack配置结构需要3个最基础文件:
- webpack 基础配置文件,暂命名为
webpack.base.js
- webpack 开发配置文件,暂命名为
webpack.dev.js
- webpack 打包配置文件,暂命名为
webpack.prod.js
当然,需要把 dev
或 prod
中的配置和 base
的配置合并起来,安装个webpack-merge
吧。
然后配置一下最熟悉的脚本运行环节吧。通过--config
来对标配置文件,通cross-env
设置环境变量
"dev": "cross-env NODE_ENV=dev webpack-dev-server --config script/webpack.dev.js",
"build": "cross-env NODE_ENV=prod webpack --config script/webpack.prod.js"
好的,初期准备工作都OK开始配置环节。
开始配置
首先是webpack的出入口。出口设置为 dist 环节简单直接上代码。
{
entry: './src/index.js',
output: {
filename: '[name].[hash:8].js',
path: rootResolve('dist'),
publicPath: '/'
},
}
顺便配置下别名。依然可以直接上代码
resolve: {
extensions: ['.js', '.json'],
alias: {
'@': rootResolve('src'),
'@assets': rootResolve('src/assets'),
}
}
然后是关键环节:loader
和 plugins
关于 loader
:
- 样式上使用
less
- 需要通过
less-loader
解析less
因为 webpack 只能读懂js - 解析完成再通过
postcss-loader
加上浏览器前缀 - 再通过
css-loader
解析css代码中的url
、@import
语法 - 最后,通过
MiniCssExtractPlugin.loader
生成.css
文件
- 需要通过
- JS 文件使用
babel-loader
,关于babel
文章太多了,暂略- 顺便使用
HappyPack
进行优化加速 - 为什么不选
thread-loader
呢? (因为名字不好听- -!
怪我咯)
- 顺便使用
- 其他文件,用
url-loader
咯。
然后 loader
配置就是这样的
{
test: /.less$/,
exclude: /(node_modules|bower_components)/,
loaders: [{
loader: MiniCssExtractPlugin.loader,
options: {
esModule: true,
hmr: process.env.NODE_ENV === 'dev', // 热更新
// publicPath: '../',
}
}, 'css-loader', 'postcss-loader', 'less-loader']
},
{
test: /.m?js$/,
exclude: /(node_modules|bower_components)/,
loader: 'happypack/loader',
options: {
id: 'babel',
}
},
{
test: /.(png|jpe?g|gif)(?.*)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 8192,
name: 'assets/img/[hash:8].[ext]'
}
}]
}
关于插件部分,首先是配合上面 loader
的相关插件:HappyPack
和 MiniCssExtractPlugin
new MiniCssExtractPlugin({
filename: "css/[name].[hash:8].css", // css 路径
}),
new HappyPack({
id: 'babel',
loaders: [{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory: true
}
}]
})
当然,我想知道运行和打包的进度: ProgressPlugin
,顺便弄个 DefinePlugin
工程化必备插件。最后webpack生成后的代码注入不能少了 HtmlWebpackPlugin
然后 base
文件的插件结构是这样的
plugins: [
new webpack.ProgressPlugin(),
new webpack.DefinePlugin({
NODE_ENV: JSON.stringify(process.env.NODE_ENV), // 当前使用环境
VERSION: JSON.stringify('0.1.0'),
}),
new MiniCssExtractPlugin({
filename: "css/[name].[hash:8].css", // css 路径
// chunkFilename: "[id].css",
}),
new HappyPack({
id: 'babel',
loaders: [{
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
cacheDirectory: true
}
}]
}),
new HtmlWebpackPlugin({ template: './src/index.html' })
]
开发环境配置
首先开发环境 api 代理必不可少。那么就是 devServer.proxy
了,顺便再定义下开发环境端口号。
devServer: {
contentBase: path.join(__dirname, "dist"),
compress: true,
port: 3333
}
目前也没有太多事情,那么 merge 下再配个 HotModuleReplacementPlugin
吧
merge(base, {
mode: 'development',
plugins: [
],
devServer: {
contentBase: rootResolve("src"),
compress: true,
port: 3333
},
plugins: [
new webpack.HotModuleReplacementPlugin()
]
})
打包环境
打包环境主要做了这几件事情
- 打包优化
- 分类文件
- 删除冗余
首先是 dll
- 定义 dll 配置文件。 比如:
webpack.dll.config.js
- 需要定义要打包的库和打包的出口
- 命名生成后的dll模块的详细要点文件
manifest.dll.json
那么 webpack.dll.config.js
内容应该是这样的
{
// 你想要打包的模块的数组
entry: {
vendor: ['three']
},
output: {
filename: '[name].dll.js',
path: distResolve('dll'), // 打包后文件输出的位置
library: '[name]_library'
// 这里需要和webpack.DllPlugin中的`name: '[name]_library',`保持一致。
},
plugins: [
new webpack.DllPlugin({
name: '[name]_library',
path: distResolve('dll/manifest.dll.json'),
context: __dirname
})
]
}
- 通过
DllReferencePlugin
+json文件
把 dll模块的详细要点告诉 webpack
在 prod
文件中添加 plugins
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require(distResolve('./dll/manifest.dll.json'))
})
- 添加脚本运行配置
"dll": "webpack --config script/webpack.dll.config.js",
运行下 npm run dll
,在 dist/dll
目录下生成dll相关文件,那么 dll
配置也完成了。顺便做一些清理工作,用下 CleanWebpackPlugin
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'assets', 'js', 'css', 'index.html', '*.js',
'!manifest.dll.json', '!vendor.dll.js' // 不删除 dll 文件
],
})
然后是代码优化,其实当 mode: 'production'
时已经做了很多代码优化相关的事情了。(我不管,我就是要优化 - -!
)
做一下 js的并行压缩吧
optimization: {
minimizer: [
new TerserWebpackPlugin({
parallel: true, // 启用并行压缩
cache: true, // 启用缓存
}),
new OptimizeCssAssetsPlugin({ // 压缩css
cssProcessorOptions: {
safe: true
}
})
],
runtimeChunk: true, // 自动拆分runtime文件
splitChunks: {
chunks: 'async',
minSize: 30000,
automaticNameDelimiter: '~',
automaticNameMaxLength: 30,
cacheGroups: {
defaultVendors: {
test: /[\/]node_modules[\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
},
}
欧耶,再配置下js的打包后路径就好了
output: { // JS 路径
path: distResolve(),
filename: 'js/[id].[chunkhash].js',
chunkFilename: 'js/[name].[chunkhash].js'
},
最后 merge
下 base
配置。在 dev
时做过了... 省略。
至此,Webpack配置已经大部分完成了,运行npm run build
打包代码,1、2、3。 3秒打包完成了。
为什么只需要3秒呢?虽然上面的配置确实做了很多优化,但是大部分事情都被表象迷惑了,具体为何下一章见。
最后
- 源码地址 https://github.com/zhongmeizhi/three-demo
- 更多实战项目:https://github.com/zhongmeizhi/z-ui
- 一个字一个字码出来的文章,原创不易,点个赞呗。
- 欢迎关注公众号「前端进阶课」认真学前端,一起进阶。