實(shí)現(xiàn)vue-cli(二):webpack實(shí)現(xiàn)項(xiàng)目打包

一、大概思路

(一)開發(fā)階段的打包構(gòu)建
  1. 配置打包的入口文件和輸出目錄等信息。
  2. 清空構(gòu)建目錄舊文件奶浦。處理js文件略就。
  3. 處理打包js/css/vue/圖片字體等捎迫。
  4. 將打包結(jié)果注入html。
  5. 啟動(dòng)服務(wù)器預(yù)覽頁(yè)面表牢,并監(jiān)聽變化窄绒。
  6. 增加eslint檢測(cè)。
  7. 配置sourceMap等信息崔兴。
(二)發(fā)布階段的打包構(gòu)建
  1. 配置打包的入口文件和輸出目錄等信息彰导。
  2. 清空構(gòu)建目錄舊文件蛔翅。處理js文件。
  3. 處理打包js/css/vue/圖片字體等(發(fā)布階段還需要對(duì)css/js進(jìn)行壓縮混淆)位谋。
  4. 拷貝public資源山析。
  5. 將打包結(jié)果注入html。
  6. 增加eslint檢測(cè)掏父。
  7. 配置sourceMap等信息笋轨。

二、“開發(fā)階段打包構(gòu)建”具體實(shí)現(xiàn)

(一)準(zhǔn)備工作
  1. 請(qǐng)確保自己本地已有npm或yarn等包管理工具赊淑,本文用npm做演示爵政。
  2. 下載該演示項(xiàng)目,或者自行vue-cli創(chuàng)建一個(gè)項(xiàng)目陶缺。
  3. 在該文件夾下空白處“按shift+鼠標(biāo)右鍵”钾挟,選中“在此處打開命令行/powershell窗口”打開命令行窗口,或者自行通過(guò)命令窗口cd到該文件目錄下组哩。
  4. 命令行輸入npm init回車等龙,自行填寫信息一路回車,最后生成package.json配置文件伶贰。
  5. 命令行輸入npm install webpack webpack-cli -D安裝webpack打包構(gòu)建工具(注意:版本不一致可能會(huì)導(dǎo)致報(bào)錯(cuò)蛛砰,本篇演示用的版本是"webpack": "5.36.2""webpack-cli": "3.3.12",詳細(xì)版本見最后附錄)黍衙。
  6. 在示例項(xiàng)目下新建webpack.config.js作為webpack的配置文件泥畅。
(二)配置打包入口和輸出等信息

在webpack.config.js中添加以下代碼,命令行輸入npx webpack運(yùn)行琅翻,默認(rèn)會(huì)去執(zhí)行webpack.config.js文件位仁,如果成功生成temp/main.js文件則成功(會(huì)有報(bào)錯(cuò)后面解決)。

const path = require('path')

module.exports = {
  entry: './src/main.js',
  output: {
    filename: '[name]_[contenthash:8].js', // 生成文件的名字
    path: path.join(__dirname, 'temp') // 生成文件放在哪方椎,output.path必須是絕對(duì)路徑
  },
  mode: 'none', // 設(shè)置webpack運(yùn)行模式聂抢,有production/development/none三種取值,不同模式會(huì)內(nèi)置不同功能
}
(三)清空輸出目錄的舊文件

如果多運(yùn)行幾次打包命令npx webpack就會(huì)發(fā)現(xiàn)棠众,生成的index.js越來(lái)越多琳疏,而我們用到的其實(shí)只有最新的那個(gè)。為了避免冗余闸拿,我們可以使用插件在每次打包之前先刪除下目錄里的舊文件空盼。npm install clean-webpack-plugin -D安裝刪除文件的插件,然后增加plugins配置新荤。配置完后再執(zhí)行打包npx webpack則只會(huì)保留最新的文件揽趾。

const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    filename: '[name]_[contenthash:8].js', // 生成文件的名字
    path: path.join(__dirname, 'temp') // 生成文件放在哪,output.path必須是絕對(duì)路徑
  },
  mode: 'none', // 設(shè)置webpack運(yùn)行模式苛骨,有production/development/none三種取值篱瞎,不同模式會(huì)內(nèi)置不同功能
  plugins: [
    new CleanWebpackPlugin(),
  ],
}
(四)添加loader處理css/js/vue/圖片/字體
  1. 處理css:由于webpack默認(rèn)只對(duì)js進(jìn)行打包處理苟呐,所以要單獨(dú)對(duì)css進(jìn)行處理。安裝css處理所需要的loader俐筋,npm install style-loader css-loader less less-loader -D掠抬。其中css-loader只會(huì)處理css,并不會(huì)將css代碼嵌入到最后打包內(nèi)容里校哎,需要再用style-loader將css嵌入到style里。
  • 多個(gè)loader時(shí)執(zhí)行順序是從下到上依次執(zhí)行瞳步,所以反過(guò)來(lái)先寫style-loader再css-loader(先處理再將結(jié)果插入闷哆,若有l(wèi)ess要先轉(zhuǎn)成css再用css-loader處理)。
  1. 處理js:webpack對(duì)js的處理只是打包合并单起,之所以能解析import export也是對(duì)模塊化做了支持抱怔,對(duì)于一些es6新語(yǔ)法特性還需要用babel進(jìn)行轉(zhuǎn)化。npm install babel-loader @babel/core @babel/preset-env -D安裝相關(guān)依賴嘀倒,記得設(shè)置@babel/preset-env才能轉(zhuǎn)碼成功,因?yàn)檗D(zhuǎn)碼插件都放在這里面。
  2. 處理vue: 安裝vue處理需要的loader和依賴奸远,npm install vue vue-loader vue-template-compiler -D制肮,vue-loader還要搭配插件VueLoaderPlugin使用。
  3. 處理字體和圖片:安裝依賴npm install file-loader url-loader -D碳胳。一般較小的資源可以用url-loader轉(zhuǎn)為base64進(jìn)行加載勇蝙,當(dāng)資源較大base64會(huì)影響打包體積影響運(yùn)行速度,所以超過(guò)大小用file-loader加載對(duì)應(yīng)路徑資源挨约。
  • 注意:在file-loader v4.3.0版本之后默認(rèn)使用了esModule語(yǔ)法味混,所以會(huì)導(dǎo)致圖片的路徑變成[object module]。解決方案可以修改圖片的引用方式<img src="require('./assets/logo.png').default"/>诫惭,更簡(jiǎn)單的直接給loader設(shè)置esModule: false翁锡。
const path = require('path')
const {CleanWebpackPlugin} = require('clean-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  entry: './src/main.js',
  output: {
    filename: '[name]_[contenthash:8].js', // 生成文件的名字
    path: path.join(__dirname, 'temp') // 生成文件放在哪,output.path必須是絕對(duì)路徑
  },
  mode: 'none', // 設(shè)置webpack運(yùn)行模式夕土,有production/development/none三種取值馆衔,不同模式會(huì)內(nèi)置不同功能
  module: {
    rules: [
      {
        test: /\.vue$/i,
        use: 'vue-loader',
      },
      {
        test: /\.js$/i,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              ['@babel/preset-env'],
            ],
          },
        },
      },
      {
        test: /\.(css|less)$/i,
        use: [
          'style-loader',
          'css-loader',
          'less-loader',
        ],
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/i,
        use: {
          loader: 'url-loader', // 用url-loader將較小的資源轉(zhuǎn)出base64加載,較大的會(huì)影響打包體積影響運(yùn)行速度
          options: {
            limit: 10 * 1024, // 超過(guò)10kb大小用file-loader加載
            name: 'img/[name].[contenthash:8].[ext]', // 指定file-loader處理生成路徑名字
            esModule: false, // 解決圖片路徑變成[object module]的問(wèn)題
          },
        },
      },
      {
        test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/i,
        use: {
          loader: 'url-loader', // 用url-loader將較小的資源轉(zhuǎn)出base64加載隘弊,較大的會(huì)影響打包體積影響運(yùn)行速度
          options: {
            limit: 10 * 1024, // 超過(guò)10kb大小用file-loader加載
            name: 'font/[name]_[contenthash:8].[ext]', // 指定file-loader處理生成路徑名字
            esModule: false, // 解決字體路徑變成[object module]的問(wèn)題
          },
        },
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new VueLoaderPlugin(),
  ],
}

經(jīng)過(guò)上述處理哈踱,再運(yùn)行npx webpack此時(shí)已經(jīng)沒(méi)有報(bào)錯(cuò)了。接下來(lái)我們就將打包出來(lái)的結(jié)果注入到html中并啟動(dòng)服務(wù)器預(yù)覽看是否正常梨熙。

(五)將打包結(jié)果注入html
  • npm install html-webpack-plugin -D安裝webpack處理html的插件开镣。plugin和loader是webpack兩個(gè)核心。loader一般用于對(duì)文件內(nèi)容進(jìn)行編譯咽扇,并將處理結(jié)果直接插入到編譯后的文件邪财。而plugin可以對(duì)文件進(jìn)行增刪改等其他loader做不到的事情陕壹,比如刪除和拷貝文件。
  • webpack中還提供了definePlugin可以用于為全局注入變量树埠,然后在html等文件中訪問(wèn)該變量糠馆,值必須是可運(yùn)行的js語(yǔ)句,即eval(變量值)不報(bào)錯(cuò)怎憋,所以如果值是字符串得加雙引號(hào)否則認(rèn)為是變量會(huì)報(bào)錯(cuò)又碌。
    依據(jù)此可以實(shí)現(xiàn)不同運(yùn)行環(huán)境下加入不同值,比如mode: 'production'時(shí)绊袋,會(huì)默認(rèn)注入process.env.NODE_ENV = 'production'用于判斷當(dāng)前運(yùn)行環(huán)境毕匀。但上面我們?cè)O(shè)置了mode: 'none'所以要自己注入這個(gè)變量。
const HtmlWebpackPlugin = require('html-webpack-plugin')
const Webpack = require('webpack')

module.exports = {
  ...,
  plugins: [
    new CleanWebpackPlugin(),
    new VueLoaderPlugin(),
    new Webpack.DefinePlugin({
      BASE_URL: '"../public/"', // 必須是可運(yùn)行的js語(yǔ)句癌别,即eval(BASE_URL)不報(bào)錯(cuò)皂岔,所以此處得加雙引號(hào)否則認(rèn)為是變量會(huì)報(bào)錯(cuò)
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV) || '"development"', // 直接讀取node環(huán)境中的變量,如果未定義則設(shè)置為development
      },
    }),
    new HtmlWebpackPlugin({
      title: '測(cè)試標(biāo)題', // 打包后html里的title
      filename: 'index.html', // 打包后的文件名
      template: './public/index.html', // 依據(jù)哪個(gè)模板文件來(lái)生成最后的html
    }),
  ],
}

增加上述代碼之后命令行輸入npx webpack打包展姐,會(huì)生成temp下對(duì)應(yīng)文件躁垛,瀏覽器手動(dòng)打開temp/index.html,如果頁(yè)面顯示正常即成功圾笨。

(六)服務(wù)器啟動(dòng)并自動(dòng)刷新
  • 運(yùn)行webpack的時(shí)候加個(gè)--watch教馆,能監(jiān)聽文件變化自動(dòng)重新打包但需要手動(dòng)刷新,可以用browser-sync temp --file "**/*"實(shí)現(xiàn)自動(dòng)刷新墅拭。但由于又要寫入磁盤再讀出磁盤活玲,會(huì)比較慢。
  • webpack-dev-server能自動(dòng)運(yùn)行打包編譯和監(jiān)聽刷新谍婉,將打包內(nèi)容寫入緩存而不是磁盤舒憾,減少了磁盤讀寫。默認(rèn)會(huì)將構(gòu)建輸出的資源作為加載文件穗熬,如果沒(méi)構(gòu)建的資源要自己配置額外資源路徑镀迂。安裝插件npm install webpack-dev-server -D,并增加以下配置唤蔗。
  • 由于自動(dòng)刷新整個(gè)頁(yè)面會(huì)丟失原操作和文本探遵,但有時(shí)我們希望保留原來(lái)輸入框的內(nèi)容只變更改動(dòng)的地方,此時(shí)就需要熱更新妓柜。模塊熱更新HMR(hot module replacement)可以實(shí)時(shí)替換改變的模塊但不影響整體運(yùn)行狀態(tài)箱季。通過(guò)設(shè)置hot: true可以開啟熱更新。
module.exports = {
  ...,
  devServer: {
    contentBase: ['public', '.'], // 額外指定找不到的資源(比如public里沒(méi)打包到temp的靜態(tài)資源)去哪里找
    port: 8080,
    open: true, // 是否自動(dòng)啟動(dòng)瀏覽器
    // hot: true, // 如果hot處理代碼有報(bào)錯(cuò)棍掐,則仍然會(huì)自動(dòng)刷新整個(gè)頁(yè)面
    hotOnly: true, // 只做熱更新藏雏,無(wú)論有無(wú)報(bào)錯(cuò)也不自動(dòng)刷新整個(gè)頁(yè)面
  },
}

如果用的是webpack-dev-server4,已經(jīng)取消了hotOnly和contentBase作煌,可以將配置改成如下

module.exports = {
  ...,
  devServer: {
    static: {
      directory: './public'
    }, // 額外指定找不到的資源(比如public里沒(méi)打包到temp的靜態(tài)資源)去哪里找
    port: 8080,
    open: true, // 是否自動(dòng)啟動(dòng)瀏覽器
    hot: true, // 如果hot處理代碼有報(bào)錯(cuò)掘殴,則仍然會(huì)自動(dòng)刷新整個(gè)頁(yè)面
  },
}

命令行運(yùn)行npx webpack-dev-server啟動(dòng)服務(wù)器赚瘦,修改文件會(huì)自動(dòng)編譯刷新則代表成功。若出現(xiàn)Cannot find module 'webpack-cli/bin/config-yargs'報(bào)錯(cuò)奏寨,要修改webpack-cli版本起意,因?yàn)閣ebpack-cli早在4.0版本后就移除了yargs,版本兼容沒(méi)做好病瞳,可以在命令行輸入npm install webpack-cli@3 -D將webpack-cli還原到3.3.12版本的版本揽咕,再次執(zhí)行npx webpack-dev-server就可以了。

(七)sourceMap配置錯(cuò)誤定位

由于現(xiàn)在運(yùn)行的文件是經(jīng)過(guò)編譯的套菜,跟我們開發(fā)時(shí)寫的代碼差異比較大心褐,如果有報(bào)錯(cuò)信息只能定位到編譯后的代碼上,而無(wú)法定位到我們開發(fā)的具體代碼位置笼踩,這點(diǎn)不利于我們調(diào)試和處理問(wèn)題。source map源碼地圖指的是編譯后代碼和源碼的對(duì)應(yīng)關(guān)系亡嫌,解決編譯之后無(wú)法查看的問(wèn)題嚎于。webpack提供了devtool可以讓我們配置sourceMap模式。

常用的sourceMap模式有eval-source-map挟冠、cheap-eval-source-map于购、cheap-module-eval-source-map等。eval-source-map生成了source-map文件能定位問(wèn)題行和列知染,cheap-eval-source-map生成了簡(jiǎn)單source-map文件只能定位肋僧,cheap-module-eval-source-map是定位編譯前文件所在。即帶cheap不能定位列信息控淡;帶module是和沒(méi)loader加工過(guò)的源代碼一模一樣嫌吠。

開發(fā)階段建議使用cheap-module-eval-source-map,因?yàn)橐话忝啃胁怀^(guò)80不需要定位列掺炭,且需要看源代碼辫诅,雖然要定位編譯前文件所在行處理多啟動(dòng)慢,但只有第一次慢后面修改不再重復(fù)處理不會(huì)慢涧狮。發(fā)布階段建議用none炕矮,即不暴露源代碼,因?yàn)橐话銘?yīng)該在開發(fā)階段就把錯(cuò)誤調(diào)試處理完畢者冤。實(shí)在擔(dān)心上線后有報(bào)錯(cuò)要調(diào)試肤视,可以用nosources-source-map只提供錯(cuò)誤的行列信息但顯示給用戶空白代碼,這樣再到自己源代碼里找行列就可以定位到錯(cuò)誤位置涉枫。

module.exports = {
  ...,
  devtool: 'eval-cheap-module-source-map', // 此處寫法和官方文檔不一樣邢滑,因?yàn)閣ebpack5之后的devtool檢測(cè)規(guī)則是^(inline-|hidden-|eval-)?(nosources-)?(cheap-(module-)?)?source-map$
}
(八)增加eslint檢測(cè)

eslint主要用于檢測(cè)代碼風(fēng)格和語(yǔ)法是否符合規(guī)范,能讓團(tuán)隊(duì)的代碼保持統(tǒng)一規(guī)范方便維護(hù)拜银。命令行輸入npm install eslint安裝eslint殊鞭,然后npx eslint --init生成eslint配置文件遭垛。npm install eslint-loader -D安裝對(duì)應(yīng)loader再增加下面loader配置。

{
  test: /\.(js|vue)$/i,
  exclude: '/node_modules/', // node_modules下的文件不需要eslint檢測(cè)
  use: 'eslint-loader',
  enforce: 'pre', // 強(qiáng)制最先執(zhí)行這個(gè)loader
},

此時(shí)在main.js里寫一些語(yǔ)法錯(cuò)誤操灿,運(yùn)行npx webpack-dev-server會(huì)看到eslint報(bào)錯(cuò)即代表成功锯仪。下面報(bào)錯(cuò)表示在main.js文件的第1行第22列缺少了分號(hào)。

D:\project\test\webpack_example\src\main.js
   1:22  error  Missing semicolon                                                          semi

如果覺(jué)得有些檢測(cè)不符合團(tuán)隊(duì)的開發(fā)習(xí)慣趾盐,可以前往剛才init生成的.eslinterc配置文件里修改rules庶喜。具體的配置規(guī)則可以前往"https://eslint.cn/docs/rules/關(guān)鍵字"查看,比如上面的關(guān)鍵詞是最后的semi(表示是否最后加分號(hào))救鲤,可以前往"https://eslint.cn/docs/rules/semi"查看修改配置規(guī)則久窟。

// 修改.eslintrc
{
    "rules": {
        "semi": ["error", "never"], // 不需要分號(hào)結(jié)尾
        "linebreak-style": ["error", "windows"] // 采用windows的CRLF換行
    }
}

至此,開發(fā)階段的webpack打包構(gòu)建已經(jīng)配置完畢本缠。

三斥扛、“發(fā)布階段打包構(gòu)建”具體實(shí)現(xiàn)

發(fā)布階段的構(gòu)建大致跟開發(fā)階段一樣,但由于發(fā)布的內(nèi)容是面向客戶的丹锹,有一些要做優(yōu)化稀颁。主要區(qū)別在以下幾點(diǎn):

  1. 不需要啟動(dòng)服務(wù)器調(diào)試。
  2. 構(gòu)建的輸出目錄不同楣黍,sourceMap等配置不同匾灶。
  3. 由于無(wú)法訪問(wèn)本地資源,需要將public等不編譯資源一起拷貝到輸出目錄租漂。
  4. 為避免源碼泄露和文件過(guò)大加載過(guò)慢阶女,css等資源要進(jìn)行壓縮混淆處理,而不是簡(jiǎn)單地注入哩治。
(一)準(zhǔn)備工作

由于開發(fā)階段和發(fā)布階段有很多類似操作秃踩,所以我們可以將部分公共配置抽離出來(lái)復(fù)用,然后通過(guò)不同變量和命令來(lái)執(zhí)行不同的打包操作业筏。

  1. 新建webpack.common.js吞瞪、webpack.dev.js、webpack.prod.js三個(gè)文件驾孔,分別用于存放公共配置芍秆、開發(fā)階段配置、發(fā)布階段配置翠勉。
  2. 將之前的webpack.config.js的內(nèi)容復(fù)制到webpack.common.js里妖啥,然后webpack.dev.js先直接簡(jiǎn)單引入導(dǎo)出。
const common = require('./webpack.common.js')

module.exports = common
  1. npm install cross-env -D安裝兼容設(shè)置環(huán)境變量的庫(kù)(window和mac不兼容NODE_ENV=development這樣設(shè)置變量)对碌,然后在package.json里的script增加以下配置(即先設(shè)置當(dāng)前環(huán)境變量荆虱,再根據(jù)對(duì)應(yīng)配置文件進(jìn)行打包):
"scripts": {
    ...,
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.dev.js",
    "build": "cross-env NODE_ENV=production webpack --config webpack.prod.js"
  },
  1. 命令行輸入npm run dev,則會(huì)直接運(yùn)行package.json中scripts.dev的命令,如果能跟之前一樣正常打開頁(yè)面則成功怀读。
(二)抽離devServer

首先npm install webpack-merge -D安裝webpack中專門用于合并配置信息的庫(kù)(比Object.assign多做了一些特殊處理)诉位,然后將webpack.common.js文件里的devServer剪切到webpack.dev.js里。再次運(yùn)行npm run dev看是否正常菜枷。

// webpack.dev.js
const common = require('./webpack.common.js')
const {merge} = require('webpack-merge') // 版本不一樣苍糠,有些是直接merge = 有些要{merge} =

module.exports = merge(common, {
  devServer: {
    contentBase: ['public', '.'], // 額外指定找不到的資源(比如public里沒(méi)打包到dist的靜態(tài)資源)去哪里找
    port: 8080,
    open: true, // 是否自動(dòng)啟動(dòng)瀏覽器
    // hot: true, // 如果hot處理代碼有報(bào)錯(cuò),則仍然會(huì)自動(dòng)刷新整個(gè)頁(yè)面
    hotOnly: true, // 只做熱更新啤誊,無(wú)論有無(wú)報(bào)錯(cuò)也不自動(dòng)刷新整個(gè)頁(yè)面
    // overlay: { // 這里配置 html 頁(yè)面是否顯示 eslint 錯(cuò)誤信息蒙版 
    //   errors: true,
    //   warnings: true,
    // },
  },
})
(三)根據(jù)環(huán)境變量配置不同內(nèi)容

新建webpack_config.js文件(記得是_不是.岳瞭,因?yàn)?code>webpack.config.js是webpack的默認(rèn)運(yùn)行文件),寫入以下內(nèi)容:

const path = require('path')
module.exports = {
  dev: {
    mode: 'development',
    outputPath: path.join(__dirname, 'temp'),
    devtool: 'eval-cheap-module-source-map',
  },
  build: {
    mode: 'production',
    outputPath: path.join(__dirname, 'dist'),
    devtool: 'nosources-source-map',
  },
}

更改webpack.common.js的以下四處內(nèi)容蚊锹,再次運(yùn)行npm run dev跟之前一樣正常打開頁(yè)面則成功瞳筏。

let config = require('./webpack_config.js')
config = process.env.NODE_ENV === 'production' ? config.build : config.dev

module.exports = {
  ...,
  output: {
    filename: '[name]_[contenthash:8].js', // 生成文件的名字
    path: config.outputPath, // 生成文件放在哪,output.path必須是絕對(duì)路徑
  },
  mode: 'none', // 此處修改為config.mode牡昆,為了方便演示暫時(shí)還用none
  devtool: config.devtool,
  plugins: [
    ...,
    new Webpack.DefinePlugin({
      ...,
      'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV || config.env), // 要是eval能運(yùn)行的語(yǔ)句姚炕,所以用JSON.stringify包裹字符串
      },
    }),
  ],
}
(四)拷貝public下的資源

npm install copy-webpack-plugin -D安裝插件,在webpack.prod.js寫入以下內(nèi)容丢烘。然后命令行輸入npm run build打包钻心,看到生成dist目錄下各文件,點(diǎn)擊index.html頁(yè)面正常打開即代表成功铅协。

const common = require('./webpack.common.js')
const {merge} = require('webpack-merge')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = merge(common, {
  plugins: [
    new CopyWebpackPlugin({patterns: [{from: 'public', to: 'public'}]}), // 拷貝public到對(duì)應(yīng)目錄,舊版本是new CopyWebpackPlugin(['public'])
  ],
})
(五)壓縮混淆資源
  1. 之前我們的css都是直接通過(guò)style-loader注入的摊沉,這樣不方便進(jìn)行專門的css處理狐史、按需加載和HMR熱更新。我們可以用mini-css-extract-plugin來(lái)將css提取到單獨(dú)的文件中说墨,npm install mini-css-extract-plugin -D安裝插件骏全,更改以下文件內(nèi)容:
// webpack_config.js
module.exports = {
  dev: {
    ...,
    extract: false,
  },
  build: {
    ...,
    extract: true,
  },
}
// webpack.common.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')

module.exports = {
  module: {
    rules: [
      {
        test: /\.(css|less)$/i,
        use: [
          config.extract ? MiniCssExtractPlugin.loader : 'style-loader',
          'css-loader',
          'less-loader',
        ],
      },
    ],
  },
  plugins: [
    ...,
  ]
  .concat(config.extract ? [new MiniCssExtractPlugin({filename: '[name]_[contenthash:8].css'})] : []),
}
  1. 上面將css單獨(dú)提取出來(lái)后,我們就可以對(duì)css和js進(jìn)行專門的處理壓縮了尼斧。其實(shí)webpack本身就會(huì)對(duì)js的打包進(jìn)行一些優(yōu)化處理姜贡,但其他資源需要我們自行處理。npm install optimize-css-assets-webpack-plugin -D安裝壓縮css的插件棺棵,正常也是將該插件放在plugin選項(xiàng)楼咳,但官方建議放在optimization里的minimizer中,這樣可以統(tǒng)一控制是否要開啟壓縮烛恤,比如mode: 'production'會(huì)自動(dòng)開啟minimizer母怜。
  • 注意:當(dāng)我們配置了minimizer此項(xiàng)后,會(huì)導(dǎo)致webpack認(rèn)為我們要自定義處理缚柏,則不會(huì)再自動(dòng)壓縮js苹熏,所以需要npm install terser-webpack-plugin -D然后手動(dòng)添加js壓縮插件terser-webpack-plugin
// webpack.prod.js增加下面內(nèi)容
const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
const TerserWebpackPlugin = require('terser-webpack-plugin')

module.exports = {
  optimization: {
    minimize: true,
    minimizer: [
      new TerserWebpackPlugin(), // js壓縮插件
      new OptimizeCssAssetsWebpackPlugin(),
    ],
  },
}

至此,發(fā)布階段的webpack打包構(gòu)建也已經(jīng)配置完成轨域。更多定制化的功能可以前往webpack官網(wǎng)查看袱耽。

四、附錄

最后干发,附上本篇演示使用的各個(gè)包的版本號(hào)朱巨。如果操作中遇到版本不兼容問(wèn)題,可以嘗試使用下方的版本:

{
  "devDependencies": {
    "@babel/core": "^7.14.0",
    "@babel/preset-env": "^7.14.1",
    "babel-loader": "^8.2.2",
    "clean-webpack-plugin": "^4.0.0-alpha.0",
    "copy-webpack-plugin": "^8.1.1",
    "cross-env": "^7.0.3",
    "css-loader": "^5.2.4",
    "eslint": "^7.26.0",
    "eslint-config-airbnb-base": "^14.2.1",
    "eslint-friendly-formatter": "^4.0.1",
    "eslint-loader": "^4.0.2",
    "eslint-plugin-html": "^6.1.2",
    "eslint-plugin-import": "^2.22.1",
    "eslint-plugin-vue": "^7.9.0",
    "eslint-plugin-vue-libs": "^4.0.0",
    "file-loader": "^6.2.0",
    "html-webpack-plugin": "^5.3.1",
    "less": "^4.1.1",
    "less-loader": "^8.1.1",
    "mini-css-extract-plugin": "^1.6.0",
    "optimize-css-assets-webpack-plugin": "^5.0.4",
    "style-loader": "^2.0.0",
    "terser-webpack-plugin": "^5.1.1",
    "url-loader": "^4.1.1",
    "vue-loader": "^15.9.6",
    "vue-style-loader": "^4.1.3",
    "vue-template-compiler": "^2.6.12",
    "webpack": "^5.36.2",
    "webpack-cli": "^3.3.12",
    "webpack-dev-server": "^3.11.2",
    "webpack-merge": "^5.7.3"
  },
  "dependencies": {
    "vue": "^2.6.12"
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末铐然,一起剝皮案震驚了整個(gè)濱河市蔬崩,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搀暑,老刑警劉巖沥阳,帶你破解...
    沈念sama閱讀 216,591評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異自点,居然都是意外死亡桐罕,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,448評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門桂敛,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)功炮,“玉大人,你說(shuō)我怎么就攤上這事术唬⌒椒” “怎么了?”我有些...
    開封第一講書人閱讀 162,823評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵粗仓,是天一觀的道長(zhǎng)嫁怀。 經(jīng)常有香客問(wèn)我,道長(zhǎng)借浊,這世上最難降的妖魔是什么塘淑? 我笑而不...
    開封第一講書人閱讀 58,204評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮蚂斤,結(jié)果婚禮上存捺,老公的妹妹穿的比我還像新娘。我一直安慰自己曙蒸,他們只是感情好捌治,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,228評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著纽窟,像睡著了一般具滴。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上师倔,一...
    開封第一講書人閱讀 51,190評(píng)論 1 299
  • 那天构韵,我揣著相機(jī)與錄音周蹭,去河邊找鬼。 笑死疲恢,一個(gè)胖子當(dāng)著我的面吹牛凶朗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播显拳,決...
    沈念sama閱讀 40,078評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼棚愤,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了杂数?” 一聲冷哼從身側(cè)響起宛畦,我...
    開封第一講書人閱讀 38,923評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎揍移,沒(méi)想到半個(gè)月后次和,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,334評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡那伐,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,550評(píng)論 2 333
  • 正文 我和宋清朗相戀三年踏施,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罕邀。...
    茶點(diǎn)故事閱讀 39,727評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡畅形,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出诉探,到底是詐尸還是另有隱情日熬,我是刑警寧澤,帶...
    沈念sama閱讀 35,428評(píng)論 5 343
  • 正文 年R本政府宣布肾胯,位于F島的核電站竖席,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏阳液。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,022評(píng)論 3 326
  • 文/蒙蒙 一揣炕、第九天 我趴在偏房一處隱蔽的房頂上張望帘皿。 院中可真熱鬧,春花似錦畸陡、人聲如沸鹰溜。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,672評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)曹动。三九已至,卻和暖如春牲览,著一層夾襖步出監(jiān)牢的瞬間墓陈,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 32,826評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留贡必,地道東北人兔港。 一個(gè)月前我還...
    沈念sama閱讀 47,734評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像仔拟,于是被迫代替她去往敵國(guó)和親衫樊。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,619評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容