花了差不多一天多的時間,重新擼了一遍webpack4.x的常用配置。
github詳細代碼地址,如有幫助,請賜我一顆小星星。 https://github.com/pomelott/webpack-multi-page-cli
基本上常用的配置都熟悉了一遍,總體上來講,為了對parcel進行反擊,webpack從4.x開始,正在朝着盡可能的簡化配置文件的方向發展。
一、首先來看下,webpack4的新特性。
1.webpack不在單獨使用,4.x版本將很多命令移動到了webpack-cli包中。若想要本地安裝使用webpack,一般需要以下兩步
(1)全局安裝webpack,webpack-cli
(2)局部安裝webpack,weback-cli
2.增加了模式區分(development,production):
開發者可通過webpack --mode development/production 進行模式切換,也可以通過在配置文件中添加mode配置項進行模式選擇。
development:開發模式,打包默認不壓縮代碼,默認開啟代碼調試
production:生產模式,上線時使用,打包壓縮代碼,不開啟代碼調試。
***若要開啟代碼調試可在配置文件中增加devtool配置項
devtool: "source-map"
3.固定入口目錄為src,與入口默認文件index.js(webpack4.x向簡化配置方向發展的第一步)。
當只有src目錄與src目錄下的index.js時,無需增加webpack.config.js,4.x版本也會將打包后文件放至新增的dist目錄下。
4. js代碼抽離時,需在config中新增optimization配置項(下面會詳細說拆分代碼的規則)
optimization: { splitChunks: { cacheGroups: { vendor: { chunks: "initial", name: "jquery", enforce: true } } } }
二、4.x版本個人習慣的項目目錄結構如下圖,整個目錄完全為動手搭建,並非用腳手架修改而成。
三、配置文件核心要點
(1)當項目需要多文件入口時,入口項需要以json的格式添加
entry: { // 多入口文件 a: './src/js/index.js', b: './src/js/index2.js', jquery: 'jquery' }
(2)當多入口文件對應多出口文件時,出口文件的name需要與入口項的key相對應
output: { path:path.resolve(__dirname, 'dist'), // 打包多出口文件 // 生成 a.bundle.js b.bundle.js jquery.bundle.js filename: './js/[name].bundle.js' }
(3)多html文件需要new多個htmlWebpackPlugin實例
// 自動生成html模板 new htmlWebpackPlugin({ filename: "index.html", title: "xxxx", chunks: ['a',"jquery"], // 按需引入對應名字的js文件 template: "./src/index.html" }), new htmlWebpackPlugin({ chunks: ['b'], filename: "index2.html", title: "page2", template: "./src/index2.html" })
(4)按依賴提取js時,4.x版本寫法與之前完全不同
// 提取js,lib1名字可改 optimization: { splitChunks: { cacheGroups: { lib1: { chunks: "initial", name: "jquery", enforce: true } } } }
在多頁使用webpack時,其實我們最頭疼的或者需求最大的就是代碼拆分問題。代碼是否拆分,怎么拆,什么情況下拆。最新的splitChunksPlugin基本能滿足我們的所有需求。
我在 webpack4.x版本splitChunksPlugin的配置項詳解與實際應用場景 中提到過,最重要的就是priority這個屬性。下面具體說下我們的實際需要:
首先需要確定的是你是想優先匹配自己定義的拆分規則還是想優先匹配webpack默認的拆分規則,若相匹配自己定義的拆分規則,則priority需要設置為正數,優先匹配默認拆分規則就設置為負數。
最終webpack會根據優先級進行打包(從大到小,從正數到負數)。
(5)引入第三方庫時,建議全局暴露。這樣在打包時,4.x會按需打包。
// 全局暴露統一入口,其他文件直接用就可以 new webpack.ProvidePlugin({ $: "jquery" }),
四、下面附上三個主要的配置文件
1.webpack.config.js
const path = require('path'); const pluginsConfig = require("./webpack.plguins.js"); const rulesConfig = require("./webpack.rules.js"); module.exports = { entry: { // 多入口文件 a: './src/js/index.js', b: './src/js/index2.js', jquery: 'jquery' }, output: { path:path.resolve(__dirname, 'dist'), // 打包多出口文件 // 生成 a.bundle.js b.bundle.js jquery.bundle.js filename: './js/[name].bundle.js' }, plugins: pluginsConfig, devServer: { contentBase: path.resolve(__dirname, "dist"), host: "localhost", port: "8090", open: true, // 開啟瀏覽器 hot: true // 開啟熱更新 }, // devtool: "source-map", // 開啟調試模式 module:{ rules: rulesConfig }, // 提取js,lib1名字可改 optimization: { splitChunks: { cacheGroups: { lib1: { chunks: "initial", name: "jquery", enforce: true } } } } }
2.webpack.plugins.js
const webpack = require("webpack"); const path = require('path'); const glob = require("glob"); //消除冗余的css const purifyCssWebpack = require("purifycss-webpack"); // html模板 const htmlWebpackPlugin = require("html-webpack-plugin"); // 清除目錄等 const cleanWebpackPlugin = require("clean-webpack-plugin"); //4.x之前用以壓縮 const uglifyjsWebpackPlugin = require("uglifyjs-webpack-plugin"); // 分離css const extractTextPlugin = require("extract-text-webpack-plugin"); //靜態資源輸出 const copyWebpackPlugin = require("copy-webpack-plugin"); module.exports = [ new webpack.HotModuleReplacementPlugin(), // 調用之前先清除 new cleanWebpackPlugin(["dist"]), // 4.x之前可用uglifyjs-webpack-plugin用以壓縮文件,4.x可用--mode更改模式為production來壓縮文件 // new uglifyjsWebpackPlugin(), new copyWebpackPlugin([{ from: path.resolve(__dirname,"src/assets"), to: './pulic' }]), // 分離css插件參數為提取出去的路徑 new extractTextPlugin("css/index.css"), // 消除冗余的css代碼 new purifyCssWebpack({ // glob為掃描模塊,使用其同步方法 paths: glob.sync(path.join(__dirname, "src/*.html")) }), // 全局暴露統一入口 new webpack.ProvidePlugin({ $: "jquery" }), // 自動生成html模板 new htmlWebpackPlugin({ filename: "index.html", title: "xxxx", chunks: ['a',"jquery"], // 按需引入對應名字的js文件 template: "./src/index.html" }), new htmlWebpackPlugin({ chunks: ['b'], filename: "index2.html", title: "page2", template: "./src/index2.html" }) ]
3.webpack.rules.js
const extractTextPlugin = require("extract-text-webpack-plugin"); module.exports = [ { test: /\.css$/, // 不分離的寫法 // use: ["style-loader", "css-loader"] // 使用postcss不分離的寫法 // use: ["style-loader", "css-loader", "postcss-loader"] // 此處為分離css的寫法 /*use: extractTextPlugin.extract({ fallback: "style-loader", use: "css-loader", // css中的基礎路徑 publicPath: "../" })*/ // 此處為使用postcss分離css的寫法 use: extractTextPlugin.extract({ fallback: "style-loader", use: ["css-loader", "postcss-loader"], // css中的基礎路徑 publicPath: "../" }) }, { test: /\.js$/, use: ["babel-loader"], // 不檢查node_modules下的js文件 exclude: "/node_modules/" }, { test: /\.(png|jpg|gif)$/, use: [{ // 需要下載file-loader和url-loader loader: "url-loader", options: { limit: 50, // 圖片文件輸出的文件夾 outputPath: "images" } } ] }, { test: /\.html$/, // html中的img標簽 use: ["html-withimg-loader"] }, { test: /\.less$/, // 三個loader的順序不能變 // 不分離的寫法 // use: ["style-loader", "css-loader", "less-loader"] // 分離的寫法 use: extractTextPlugin.extract({ fallback:"style-loader", use: ["css-loader", "less-loader"] }) }, { test: /\.(scss|sass)$/, // sass不分離的寫法,順序不能變 // use: ["style-loader", "css-loader", "sass-loader"] // 分離的寫法 use: extractTextPlugin.extract({ fallback:"style-loader", use: ["css-loader", "sass-loader"] }) } ]
***習慣用webpack之后,會很方便。不要怕出問題,解決問題后的成就感會讓你更加強大。github上有本次4.x版本的demo,歡迎小伙伴提問題,如果覺得還不錯,請給星!!