關於 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
- 一個字一個字碼出來的文章,原創不易,點個讚唄。
- 歡迎關注公衆號「前端進階課」認真學前端,一起進階。