讀懂webpack4,看這一篇就夠了

概述,在webpack裏面有四個概念: 入口、出口、插件和loader,進行模塊化打包,支持CMD、ADM、commonJS、import等模塊化操做。css

安裝說明:在webpack安裝的時候,須要先安裝一個全局的webpack,而後在須要的文件夾中安裝局部的依賴,webpack webpack-cil腳手架,在webpack3的版本中,它們是集成在一塊兒。本次筆記是針對於:webpack4.x以上的版本html

npm install webpack -g 	//先安裝全局的webpack,安裝完成後,才能夠實驗webpack命令,直接打包
npm install webpack webpack-cli  -D  // 在須要的目錄安裝webpack

webpack  // 在cmd或者vscode中運行這個,就能夠打包了,其它的配置,且看後面
複製代碼

安裝完成後,須要在項目根目錄新建一個webpack-config.js的配置文件;沒有新建這個文件,也能夠打包,由於webpack有默認配置。前端

若是沒有安裝全局webpack的話,就沒法直接使用webpack直接打包,固然,也能夠單獨是配置腳本,例:vue

scripts: {
    dev: webpack --config webpack-config.js
}
複製代碼

在4.0之後的版本里面,新增了一個多入口打包命令:webpack app.js app1.ja -o bulid.jsnode

在webpack中有生產模式(production)和開發模式(development),默認爲開發設置,用,mode參數去設置模式,例:react

module.exports = {
  mode: 'production' // 模式選擇,生產和開發兩種
};
複製代碼

特別說明:須要指定mode屬性,否則控制檯會報出一個警告信息jquery

入口(entry)

入口(entry point),表示 webpack 應該使用哪一個模塊;進入入口之後,webpack 會找出有哪些模塊和庫是入口起點(直接和間接)依賴的。webpack

入口能夠是單入口和多入口(使用一個數組或者對象表示),在實際操做中,爲了便於優化以及首屏加載問題,會更傾向於第三種方式,既對象的形式。ios

可是使用對象寫法(entry代碼分離),會有一些小問題;假設entry引入了2個js文件,分別是a.jsb.js,可是這個兩個文件都引入了同一個依賴,打包之後,就會形成代碼重複,很是不利於優化,因此須要使用SplitChunksPlugin來進行防止重複或者是動態倒入的方法。點擊查看這種方式的坑點:代碼分離git

module.exports = {
  entry: './app.js' // 寫法一
  entry: ['./app.js, main.js'] //寫法二
  entry: {
    app: './app.js',
    main: './main.js'
} //寫法三
};
複製代碼

出口(output)

若是使用(output)屬性表示,這個屬性是用來告訴webpack輸出它所建立的內容,默認的目錄是dist文件夾,在項目的根目錄中,也能夠指定一個目錄導出。

const path = require('path');
module.exports = {
  entry: './path/to/my/entry/file.js', // 入口
  output: { // 出口
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js' // 單文件合併的寫法
    filename: '[name].js', // 多入口多文件
    chunkFilename: [name][contenthash].js, // 防止緩存,只有在更新之後纔會生成隨機碼
    publicPath: 'CDN地址' // 設置CDN服務器地址, 理論上是能夠直接打包到CDN服務器上,前提是有權限
  }
};
複製代碼

入口文件有配置的,就走filename這個屬性,若是是其它文件導入的,就走下面這個,既chunkFilename,在使用的時候,目的就是解決代碼更新,而瀏覽器讀取緩存獲取不到更新。

output中,filename屬性是用來告訴webpack打包後的文件名稱;而path是告訴webpack須要建立的文件夾的位置信息,這個要調用node裏面一個模塊,既path模塊,__dirname是node裏面的一個關鍵字,表示路徑,絕對路徑

提示:在webpack裏面,多個入口若是要合併文件,只能使用數組的方式; 若是須要打包多文件的時,入口須要使用對象,出口使用一個動態的寫法,如上代碼"多入口文件", [name].js,若是入口是一個對象,出口必定是一個動態寫法,不然就會致使打包不正常。

loader

loader 讓 webpack 可以去處理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 能夠將全部類型的文件轉換爲 webpack 可以處理的有效模塊,而後你就能夠利用 webpack 的打包能力,對它們進行處理。

loader的執行順序,是從下到上,從右到左的執行順序,因此在設置loader的時候,順序不能放錯,不然,可能會致使打包異常。

我的理解: loader就至關因而一個翻譯器,將咱們寫的代碼,進行翻譯並處理。使用方法,以下:babel爲例

注意:在lodaer裏面,配置正則(test)的時候,必定不能加引號,不然會提示lodaer錯誤。

babel

介紹:babe就是將ES6轉成ES5的一個編譯器,須要安裝3個依賴;雖然Babel能夠將ES6的語法轉成ES5的語法,可是若是是ES6+裏面的內置API就沒法去轉換了,所以安裝一個墊片@babel/polyfill,它主要是爲了兼容低版本的瀏覽器,

babel-loader @babel/core  // 主要是語法轉換
@babel/preset-env  // 這個用來指定ES的版本
@babel/polyfill // 全局墊片,用於轉換內置API支持ES5的語法
/* 局部墊片須要安裝的依賴項 */
@babel/plugin-transform-runtime
@babel/runtime
複製代碼

webpack配置方式

module: {
  rules: [
    {
      test: /\.m?js$/, // 匹配文件的後綴名
      exclude: /(node_modules|bower_components)/, // 須要剔除的目錄
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'], // 墊片使用
          plugins: ['@babel/plugin-proposal-object-rest-spread'] //額外的
        }
      }
    }
  ]
}
複製代碼

關於屬性use的操做,若是配置項目不是不少的時候,能夠不用use這個屬性,它們兩個是等價的,直接寫,例:

rules: [{
    test: /\.m?js$/, // 匹配文件的後綴名
    loader: 'babel-loader', // 加載的loader
    exclude: /(node_modules|bower_components)/, // 須要剔除的目錄
    options: { 	//配置項
   		presets: ['@babel/preset-env'], // 默認寫法,不使用配置的寫法
        presets: [["@babel/preset-env", { // 第二種寫法,配置一個babel/polyfill墊片
        useBuiltIns: "usage", // 按需加載 entry | usage
        targets: {
          chrome: "68"  // 瀏覽器目標,也能夠跟隨一個瀏覽器的市場份額
        }
      }]
      ]
    }
}]
複製代碼

關於@babel/polyfill的使用:先安裝,須要在被打包的文件中引入 @babel/polyfill這個模塊,默認是會打包全部的API內置模塊,所以須要一個按需加載,寫法:useBuildIns: 'usage'

默認會報出一個警告,解決方案:若是配置了usage的話,就不須要在被打包的文件種引入@babel/polyfill,若是須要引入的話:則須要用entry替換(局部方式,按照文件需求)

關於局部墊片的使用說明:若是是寫的一個插件,就不能使用全局墊片,使用局部墊片須要有兩個依賴@babel/plugin-transform-runtime@babel/runtime

.babelrc配置方法

在項目根目錄須要新建一個單文件,文件名:.babelrc,格式是一個標準的JSON,因此須要使用標準的JSON格式,下面已局部墊片配置爲例:

{
	"presets":["@babel/preset-env"],
	"plugins": [["@babel/plugin-transform-runtime", { 
         "absoluteRuntime": false,
         "corejs": 2, // corjs須要改爲2,不改的話會形成打包異常,官方默認是false,可選數字和布爾
         "helpers": true,
         "regenerator": true,
         "useESModules": false
      }]
  ]
}
/* ================ 正常模式下 使用文件名的方式 配置 ========================*/
{
      "presets": [["@babel/preset-env", {
          "useBuiltIns": "usage",
          "targets": {
          "chrome": "68"  // 瀏覽器目標,也能夠跟隨一個瀏覽器的市場份額,也能夠是:last 100 versions
        }
      }]
      ]
}
複製代碼

關於異常的處理:corejs官方的默認值是false,可是這樣會有異常,結果就是不會轉換;所以在corejs的屬性後面要跟上一個數字2,可是這樣,仍是不行,所以須要下載一個@babel/runtime-corejs2依賴項,用來改變以前的@babel/runtime

注意:在設置presets屬性的時候,若是須要配置,第二個對象是放在嵌套數組裏面,如:[['xxx',{} ]],而且,不能夠在在webpack裏面設置了之後,再去單獨的.babelrc裏面去設置,根據試驗證實:會報錯。

插件(plugins)

想要使用一個插件,你只須要 require() 它,而後把它添加到 plugins 數組中。多數插件能夠經過選項(option)自定義。你也能夠在一個配置文件中由於不一樣目的而屢次使用同一個插件,這時須要經過使用 new 操做符來建立它。

這是官方的說法,我本身的理解就是,給webpack擴展一個功能,這個功能極其強大,能夠用來處理各類各樣的任務,插件的使用方法以下:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 經過 npm 安裝的模塊
const webpack = require('webpack'); // 用於訪問內置插件
const path = require('path') //這是一個文件路徑的內置模塊,在使用resolve屬性時,就必需要有這個

const config = { // 多文件配置的寫法
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
        template: './src/index.html'
    })
  ]
};
module.exports = config 
複製代碼

HtmlWebpackPlugin的使用

HtmlWebpackPlugin插件,該插件將爲你生成一個 HTML5 文件, 其中包括使用 script 標籤的 body 中的全部 webpack 包。 使用的時候,須要安裝這個插件html-webpack-plugin,基本具體配置以下:

var HtmlWebpackPlugin = require('html-webpack-plugin'); // 引入插件
plugins: [
    new HtmlWebpackPlugin({ // 能夠配置更多的值,好比title
        title: 'webpack', // 生成HTML標題
        templat: './index.html' // 配置的模板文件
        hash: true, // 防止緩存,給生成的JS文件添加一個hash值,包含css
        cache: true // 僅在內容被更改時才更新文件
        inject: true, // JS注入的位置,true,默認底部 
        chunks:['xxx', 'entry入口文件名'], // 多入口文件,會根據配置生成JS文件,默認所有引用 
        minify: {
        	removeAttributeQuotes: true, // 是否移除屬性的引號 默認false
    }
    })
]
複製代碼

參考資料: npm原文連接webpack4 之html-webpack-plugin。更多配置查看前面的NPM原文連接

clean-webpack-plugin的使用

clean-webpack-plugin插件能對配置的輸出文件進行清除,在build命令開始執行的時候,會自動的去檢查,若有有就會去先清除掉,這樣就永遠地保證了這個目錄裏面的文件都是最新的。可是也能夠自定義刪除某個目錄,文檔請戳這裏

const { cleanWebpackPlugin } = require('clean-webpack-plugin') // 先引入這個包,須要使用這種方式
plugins: [
	new cleanWebpackPlugin()  // 使用,默認不須要進行傳參, 根據實測,在3.X的版本,能夠直接引入
]
複製代碼

多個loader或多插件配置

若是要使用多個lodaer,只須要將規則rules屬性下面,放一個數組,裏面能夠有多個對象

module: {
rules: [{  // 關於多個loader配置以下,每一個loader都是一個對象
		test: /\.tsx?$/,
		use: 'ts-loader',
		exclude: /node_modules/ 
	},{
      test: /\.m?js$/, // 匹配文件的後綴名
      exclude: /(node_modules|bower_components)/, // 須要剔除的目錄
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: ['@babel/plugin-proposal-object-rest-spread']
        }
      }
    }]
}
複製代碼

提示:其實,每個loader或者插件均可以使用單文件的方式,這樣可讓webpack文件變得不是那麼的龐大,可是會形成項目根目錄文件的變得不少,具體根據本身得項目來進行配置。

關於TS文件的打包

在轉換TS文件的時候,須要下載typescript ts-loader的依賴,安裝好之後,須要在項目根目錄新建一個爲tsconfig.json的JSON文件,配置以下:

{
  "compilerOptions": {
    "outDir": "./dist/",  // 輸出的文件,若是webpack已經配置了,就不須要了
    "noImplicitAny": true, 
    "module": "es6",	// 已什麼模塊的方式引入文件,主要有ES6和commonJS
    "target": "es5",	// 須要編譯成什麼類型的語法,ES5
    "jsx": "react",	  // 使用jsx語法,
    "allowJs": true   // 在TS文件種是否存在ES的語法,默認true
  },
  "include": ['./src/', './'], // 引入的文件目錄,須要編譯的文件
  "exclude": /node_modules/  // 剔除不須要編譯的目錄,多個使用(xx|xx)這種方式
}
複製代碼

編譯typescriptwebpack的配置以下:

module: {
	rules: [{
		test: /\.tsx?$/,
		use: 'ts-loader',
		exclude: /node_modules/ 
	}]
},
複製代碼

lodash是一個一致性、模塊化、高性能的 JavaScript 實用工具庫,主要用於代碼類型約束。在TS裏面使用types/lodash能夠對TS進行類型約束。**提示:**lodash具備針對性,若是須要對jquery進行類型約束,則須要下載對應的lodash依賴包。

圖片打包

在圖片打包之前,須要下載一個loader,使用file-loader能夠對圖片進行打包,webpack經常使用配置以下:

module: {
	rules: [{
		test: /\.(png|jpg|gif)$/,
        use: [{
            loader: 'file-loader',
            options: {
            	name: '[path][name].[ext]' // 自定義名字,[name]名字[ext]擴展名,還能夠加混淆好比哈希值
                outputPath: 'images/'  //將打包的文件,生成打包相對文件(dist)的images/的目錄下
            }
		}]
	}]
}
複製代碼

說明:圖片打包,默認文件名使用哈希進行混淆,也能夠自定義配置。具體查看webpack官方的url-loader說明,示例上僅僅只是顯示了一部分。

若是圖片須要進行BASE64的打包,須要下載url-loader的一個loader,可是須要注意的是,file-loadeurl-loader的處理是同樣的,惟一不同的就是url-loader要比file-loade的功能更增強大,使用的方法和file-loade的方法如出一轍,並無什麼區別,可是url-loade擁有更多的配置項。

module: {
	rules: [{
		test: /\.(png|jpg|gif)$/,
        use: [{
            loader: 'url-loade',
            options: {
            	name: '[path][name].[ext]', // 自定義名字,[name]名字[ext]擴展名,還能夠加混淆好比哈希值
                outputPath: 'images/',  //將打包的文件,生成打包相對文件(dist)的images/的目錄下
                limit: '1024', // 圖片打包base的大小限制,單位是字節
            }
		}]
	}]
}

複製代碼

使用url-loader會默認的將圖片打包成了base64的文件,可是在正常狀況下,只有在圖片比較小的話,纔會打成base的格式,所以須要在options裏面進行圖片大小進行配置

CSS模塊化打包

在打包css的時候,須要下載一個css-loaderstyle-loaderlodaer去作編譯,若是要使用預編譯,則須要安裝對應的預編譯loader。例如:sass須要 sass-loadernode-sass這兩個loader,根據實驗,只須要sass-loader就能夠了。

css-loader用來打包css

style-loader用來掛在頁面,將這個loader自動掛在到html頁面上,通常方式在html頭部

基本配置信息以下(包含了sass預處理器):

module.exports = {
    module: {
    rules: [{
        test: /\.css$/,  // /\.sass$/
        use: [ 'style-loader', 'css-loader' , 'sass-loader']
      }]
  }
}

複製代碼

給CSS3添加前綴須要使用postcss-loaderlodaer和 autoprefixer插件,繼續使用上面的例子,基本配置以下:

module.exports = {
    module: {
    rules: [{
        test: /\.css$/,  // /\.sass$/
        use: [ 'style-loader', 'css-loader' , 'sass-loader','postcss-loader'] // 寫法1
        use: [ 'style-loader', 'css-loader' ,'sass-loader',{ // 寫法2,能夠對每一個lodaer作單獨配置
        	loader:'postcss-loader',
        	options: {
            	plugins: [
                	require("autoprefixer") /* 生成瀏覽器前綴 */
             ]}
    	}] 
      }]
  }
}

複製代碼

若是要讓它自動添加前綴的話,須要在項目根目錄新建一個文件(也能夠是其它文件夾,全局配置通常都放在根目錄),postcss.config.js,在裏面進行一個配置,也能夠如上代碼那樣,寫在webpack.config.js中;基本配置信息以下:

module.exports = {
	 plugins: [ //插件的方式
     	 require'autoprefixer'// 加載模塊 默認寫法
         require('autoprefixer')({ // webpack或者postcss.config.js配置,
    		overrideBrowserList: 'last 100 versions'
		})
     ]
}

複製代碼

autoprefixer在默認的配置下,只能自動的添加webkit的前綴信息,若是須要添加更多的配置,還須要添加額外的參數。

須要在package.json裏面添加一個屬性,屬性名是browserslist,對應的是一個數組,裏面填入瀏覽器、或者node版本的名稱,例如:"last 100 versions"

若是須要在webpack裏面配置的話,就須要使用overrideBrowserList屬性去替換browserslist這個屬性,不然在編譯的時候,webpack會有錯誤提示。關於browserslist的具體用法,請點擊這裏

CSS模塊化機制,簡單配置:

module.exports = {
    module: {
    rules: [{
        test: /\.css$/,  // /\.sass$/ // 匹配的後綴名
        use: [ 'style-loader', {  // 配置須要的加載器,loader
            loader: 'css-loader',
            options: {
                modules: {
                 	 localIdentNane: '[name]_[hash:base64:10]' // 自定義class的名字,bese須要截取
                }
            }
        }, 'sass-loader']
      }]
  }
}

複製代碼

若是開啓了模塊化操做,那麼在模塊化導入的時候,文件就只能是局部的方式導入,不然webpack在編譯的時候,會出錯,例子以下:

import 'xxx.css'  // 全局引入
import xxx from 'xxx.ss' // 局部引入

複製代碼

打包字體:打包字體和打包文件同樣,loader用的也是打包圖片的那個file-loader

module: {
	rules: [{
		test: /\.(woff|woff2|svg|ttf|eot )$/,  // 字體文件後綴名
        use: [{
            loader: 'file-loader',
            options: {
            	outputPath: 'font/'  //生成的文件夾,將打包的文件,放在裏面
                name: [name].[ext]   // 修改輸出文件名,這樣就默認原來的文件名和後綴名
            }
	}]
	}]
}

複製代碼

devServer經常使用配置

webpack-dev-server 可以用於快速開發應用程序,因此簡稱devServer;devServer是用來提升開發效率的,不是用devServer來作打包,它提供了一些配置項,能夠用於改變devServer的默認行爲,要配置devServer,除了能夠在配置文件裏經過devServer傳入參數,還能夠經過命令行傳入參數。

/* 截取的vue cli的例子 經過命令傳遞的參數*/
"dev": "webpack-dev-server --host 0.0.0.0 --inline --progress --config build/webpack.dev.conf.js",

複製代碼

可是須要注意的是:devServer 只適用於開發模式

開啓本地服務

webpack開啓本地服務器安裝一個內置插件webpack-dev-server來幫咱們開啓一個本地服務,雖然webpackDevServer插件是內置的,可是依然須要下載,只是不須要引入,須要在webpack.config.jspackage.json文件進行配置,配置內容以下:

/* webpack.config.js 配置 */
module.exports = {
	devServer: {
		contentBase: './dist' // 配置打包的路徑
        open: true, // 設置是否默認打開
        prot: "8080", // 端口
        hot: true , // 開啓熱更新
	}
}
/* package.json 配置 */
"scripts": {
    "dev": "webpack-dev-server --open"
}

複製代碼

在正確配置了webpack-dev-server之後,從dist目錄中提供文件,默認地址是:localhost:8080,也能夠自定義配置,配置方案如上代碼。更多配置點擊這裏,可是這種方法,會更新全部數據,能夠理解成是"頁面刷新"

webpack-dev-server在編譯後不會寫任何輸出文件。相反,它將捆綁文件保存在內存中併爲它們提供服務,就好像它們是安裝在服務器根路徑上的真實文件同樣。若是您的頁面但願在不一樣的路徑中找到捆綁包文件,則可使用publicPathdev服務器配置中的選項更改此選項。

webpack 熱更新

在使用webpack熱更新的時候,須要有一個插件HotModuleReplacementPlugin,簡稱是HMR,這個插件是webpack集成的一個內置插件,在使用的時候,不須要下載,可是要導入webpack

可是HotModuleReplacementPlugin這個插件不能用於生產模式,熱更新也是devServer裏面的一個小項。 HotModuleReplacementPlugin裏面的配置項,能夠忽略,官方說是實驗性的,不推薦配置。

const webpack = require('webpack') 
plugins:[
 	new webpack.HotModuleReplacementPlugin({
		multiStep: true, // 將分兩步構建 - 首先編譯熱更新塊,而後編譯剩餘的普通資產
		fullBuildTimeout: Number // 時間,表示啓用 multiStep 這個之間的延遲
        requestTimeout: Number // 時間(毫秒) 用於下載清單的超時時間
	});   
 ]

複製代碼

請注意,webpack.HotModuleReplacementPlugin徹底啓用HMR是必需的。若是webpack或者webpack-dev-server使用該--hot選項啓動,則會自動添加此插件,所以您可能不須要將此添加到您的webpack.config.js

"dev": "webpack-dev-server --host 0.0.0.0 "  // 上述說明的實例,不須要webpack.config.js配置

複製代碼

webpack 預加載

webpack 反向代理

dev-server 使用了很是強大的 http-proxy-middleware 包。更多高級用法,請查閱其文檔;在咱們作開發的時候,會由於跨域問題致使沒法進行數據請求,所以須要藉助wenpack提供的反向代理,既porxy,使用方法以下:

/* 省略其它代碼 */
devServer: {
    porxy: {
    	"/api": "http://localhost:3000"// 基礎用法,將/api綁定到目標服務器。
        "/api": { // 採用配置的用法,用法二
         	target: "http://localhost:3000", // 目標服務器
            pathRewrite: {"^/api" : ""},  //路徑重寫,這樣在前端訪問的時候,就不須要傳/api
            secure: false, // 配置是否須要使用https的方式,默認是不容許
        }
    }, // 多個API請求同一服務器的寫法
     porxy:[{
     	context: ["/auth", "/api"], // 多個請求
  		target: "http://localhost:3000", // 目標服務器
     }]
}
/*** 前端請求,已axions爲例 ***/
   axios.get('/api/xxx').then(red => { xxx })  
 axios.get('// xxx').then(red => { xxx })  // 配置請求的方式訪問 忽略掉/api

複製代碼

假設有多個API請求都在同一個服務器,可使用context上下文的方式跟上一個數組,代碼如上例子,關於webpack proxy的更多配置,請戳這裏訪問官網更多說明。

webpack 預加載

SourceMap的設置

其實配置devtool就是在配置SourceMap,意爲:源文件映射,可以快速找到代碼出錯的位置,可是這種方式,須要打包完了之後才能看到是否出錯;可是也有折中的解決方案,須要在package.json裏面設置一個腳本,能夠自動的爲咱們打包,但它是一個文件協議,正常來講,頁面須要手動刷新,全部仍是使用devServer的方式會比較好點兒。

module.export = {
    /* cheap-module-eval-source-map 開發環境使用,速度快,包含三方模塊 僅提示行錯誤*/
    /* cheap-module-source-map 生產環境使用, 其實也能夠不使用*/ 
    /* source-map 源文件映射 inline-source-map(精準告訴你哪行那列出錯)*/
    devtool: 'cheap-module-eval-source-map'
}
/*================================= package.json ===============================*/
"scripts": {
    "dev": "webpack --watch" 
  }

複製代碼

devtool您可使用SourceMapDevToolPlugin, 而不是使用該選項,EvalSourceMapDevToolPlugin由於它有更多選項。切勿同時使用devtool選項和插件,該devtool選項在內部添加插件,所以您最終會將插件應用兩次。

devtool您可使用SourceMapDevToolPlugin, 而不是使用該選項,EvalSourceMapDevToolPlugin由於它有更多選項其實這句話,我也不太理解是什麼意思? 若是須要更加細粒度的控制,就使用SourceMapDevToolPlugin這個插件,可是不能同時使用,緣由上面也說了。 其實就我我的以爲,自帶的就夠了。

Tree Shaking的配置

Tree Shaking翻譯過來就是搖晃樹枝 ,因此簡稱搖樹;舉個簡單的例子:秋天的馬路,馬路兩邊種了不少行道樹,有的葉子枯黃、有的葉子任然是綠色,由於枯黃的葉子隨風飄落,爲了更好的解決落葉的問題,就找了一個大型的器械,抓着樹幹使勁搖晃,枯黃的葉子也就掉落了下來,剩下的就是不易掉落的綠色葉子。

可是反過來能夠這樣理解,就是說,對於webpack來講,入口就至關因而一棵樹幹,入口上面有不少模塊,這些模塊就是樹枝,可是這些依賴模塊並無所有使用,或者只使用了模塊中的某一個功能,這時就須要藉助Tree Shaking它將不須要的模塊給搖掉,也就是說:在打包後文件裏面,代碼都是精簡且須要的。原理請戳這裏:Tree-Shaking性能優化實踐 - 原理篇

tree shaking 是一個術語,一般用於描述移除 JavaScript 上下文中的未引用代碼(dead-code)。它依賴於 ES2015 模塊系統中的靜態結構特性,例如 importexport。這個術語和概念其實是興起於 ES2015 模塊打包工具 rollup

新的 webpack 4 正式版本,擴展了這個檢測能力,經過 package.json"sideEffects" 屬性做爲標記,向 compiler 提供提示,代表項目中的哪些文件是 "pure(純的 ES2015 模塊)",由此能夠安全地刪除文件中未使用的部分。

說了這麼多? 那在webpack裏面應該怎樣使用呢?須要在package.json中配置

{
  "sideEffects": false, // 簡單版本,
  "sideEffects": [ // 使用數組的方式,我的理解:就是將不須要搖的東西給剔除出來,。
      "@babel/polyfill",
      "./src/some-side-effectful-file.js",
      "*.css"
  ]
}

複製代碼

這樣只是標記「未使用代碼(dead code)」,可是須要是在編譯後(bulid)刪除,所以:咱們須要切換到生產模式(production)來表示,命令模式(--optimize-minimize);使用配置的方式,代碼以下:

mode: 'production',  // 必須是生產模式
optimization: {	 // 設置刪除爲標記的 未使用代碼,也就是死代碼
	usedExports: true
}

複製代碼

總結:Tree Shaking只在生產模式有效,開發模式無效,而且只能使用ESmodul的方式,詳細說明請戳這裏

單獨的webpack配置

在vue cli 2.x的版本里面有不少webpack配置,一開始我也不知道爲何須要這麼配置,經過後來的瞭解才知道,在webpack裏面有不少模式,好比:生產模式、開發模式,介於它們之間的還有各類配置文件、公共模塊等,如下是vue cli的webpack配置目錄。

.
|—— vue cli
|—— config
|	|——	dev.env.js
|	|——	index.js
|	|——	prod.env.js
|	|__	test.env.js
|——	build
|	|——	build.js
|	|——	check-versions.js
|	|——	utils.js
|	|——	vue-loader.conf.js
|	|——	webpack.base.conf.js
|	|——	webpack.dev.conf.js
|	|__	webpack.prod.conf.js
|
.

複製代碼

但是有這麼多的單獨的文件,最終須要怎麼才能合併在一塊兒呢? 是直接引入仍是須要使用插件呢?這裏須要使用一個插件,這個插件的名字是:webpack-merge,在使用它的時候,須要先去安裝這個插件。

若是將上面的目錄進行一個拆分,假設就只有webpack.prod.conf.jswebpack.dev.conf.jswebpack.base.conf.js這麼三個文件,其中webpack.base.conf.js是一個公共文件,另外兩個表示生產模式和開發模式。使用webpack-merge的方法以下:

/* ======= 以生產模式爲例 webpack.prod.conf.js======= */
const merge = require('webpack-merge');
const common = require('./webpack.prod.conf.js');

module.exports = merge(common, { 
	mode: 'production',
	devtool: 'source-map'
});

複製代碼

還須要在npm裏面進行配置,仍然已vue cli目錄爲例,在package.json中加入如下內容:

scripts": {
	"dev": "webpack-dev-server --open --progress --config build/webpack.dev.conf.js",
	"build": "webpack --config build/webpack.prod.conf.js"
}
/* --progress 顯示進度條的意思 */

複製代碼

環境變量的使用

就只想使用一個文件入口,在裏面配置一個環境變量,而後就能按照本身的須要,產生不一樣的編譯結果,實施方法能夠按照以下操做。

那裏面的commonConfig文件和prodConfig還有這個devConfig它們也是一個單獨的文件,爲了不一個文件很大,因此在使用的過程當中,仍是單獨分開寫的比較好,只不過在具體配置的時候,使用一個環境變量來判斷。

module.export = (env) => {
    if(env && env.production){ // 條件判斷
        return merge(commonConfig, prodConfig); // 生產模式(線上模式)
    } else {
        return merge(commonConfig, devConfig); // 開發模式
    }
}

複製代碼

看了上面的代碼,會想到一個問題,條件判斷的變量env && env.production是從哪裏來的,其實這個變量是從package.json``裏面配置得來的,也就是說:若是須要使用這種方式的話,就須要去更改啓動腳本,代碼以下:

scripts": {
	"dev": "webpack-dev-server --open --progress --config build/webpack.base.conf.js",
	"build": "webpack --env.production. --config build/webpack.base.conf.js"
}
/* --progress 顯示進度條的意思 */

複製代碼

能夠很清除的看到devbuild這兩個方法啓動的目錄文件都是同一個,可是在build裏面多了一個env.production這個屬性,其實,這個變量就是上面的條件判斷語句所須要的參數。

環境變量還能夠這樣使用,就nodeJS提供的process.env.NODE_ENV,具體的時候方法,參考簡書NodeJs/Vue項目中對process.env的使用

在Webpack中配置Esint

在不少時候,咱們都須要使用eslint來幫助咱們進行代碼檢查和規範,這樣每每在團隊中,能作到風格統一,很是有利於團隊協做、後期維護等,但配置eslint是很是繁瑣的,下面一塊兒來看看,咱們如何在webpack中如何配置eslint吧?在慕課手記中也有關於自定義的詳細說明,更多查看請戳這裏

eslint在使用前,須要先安裝eslint這個包,更多安裝方法戳這裏查看官方教程,安裝方法以下:

npm install eslint --save-dev // 下載eslint這個安裝包
npx eslint --init // 運行這個命令進行eslint的詳細配置

複製代碼

關於eslint配置說明,當運行npx eslint --init的時候,會彈出以下信息:

? How would you like to use ESLint? (Use arrow keys)  //如何配置eslint這個文件,你想如何使用
  To check syntax only  // 僅檢查語法
> To check syntax and find problems // 檢查語法並找出問題
  To check syntax, find problems, and enforce code style //檢查語法、發現問題和強制代碼樣式
/* 我選擇的是檢查語法並找出問題,而後就有了下面的配置信息 */

? What type of modules does your project use? // 你想使用什麼類型的模塊呢?
  JavaScript modules (import/export) // 基於ES6
> CommonJS (require/exports)	// 這個主要是node中使用
  None of these // 這些都不是 

  /* 由於在個人實驗中,用的是vue,所需須要使用esmodule這種語法,而後彈出的信息以下 */
  ? Which framework does your project use? (Use arrow keys) // 你想使用那個框架
   React
 > Vue.js  // 由於我是vue,全部選擇vue
  None of these // 其它框架
  
  /* 當選擇vue後,配置如以下,問你是在那個地方運行,能夠多選,使用空格點亮,而後回車 */
  ? Where does your code run? (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Browser // 瀏覽器
 ( ) Node    // node 
/* 當我選擇之後,會出現以下配置 固然是使用JS文件的方式,我的愛好*/
? What format do you want your config file to be in? (Use arrow keys) // 使用什麼文件做爲配置文件
> JavaScript
  YAML
  JSON

  /* 問你是否想安裝它們,這裏固然選擇是了 */
  ? Would you like to install them now with npm? (Y/n) // y 基礎配置過程就完畢了

複製代碼

當一些列配置完畢後,會發如今項目的根目錄中有一個.eslintrc.js的配置文件,這個文件就是eslint的配置文件啦,更多配置請戳這裏,也能夠選擇第三方公司的編碼配置,安裝方法參考eslint配置(使用Airbnb編碼規則),比較變態的就是airbnb規則了,很是的嚴格。

雖然這樣在vscode(前提是webpack中有插件)中可使用了,可是對於其它的代碼編輯器,卻不會怎麼報錯? 因此還須要下載一個eslint-loader才能夠,具體操做方法以下:

npm install eslint-loader --save-dev

複製代碼

下載好了之後,基本配置以下,可是必定要將eslint-loader放在最後面,由於loader的執行順序是從後往前:

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ["babel-loader", "eslint-loader"] 
      }
    ]
  }
};

複製代碼

僅僅是這樣(若是不作以下配置,只能在cmd控制檯顯示),仍是不行滴,還須要一點兒額外的其它配置,配置以下:

module.exports = {
  devServer: {
    overlay: true  // 在瀏覽器上彈出一個層,也就是在瀏覽器中顯示全屏覆蓋
  }
};

複製代碼

但都知道在vue cli2 的版本中,當檢測到警告信息,會輸出在瀏覽器的控制檯顯示,可是這個問題,我還木有解決,有知道的小夥伴,能夠告訴我如下。

overlay:{
    warnings: false, 
    errors: true
}

複製代碼

我也按照vue cli源代碼進行了一個配置,發現並無按照個人意願來。

打包第三方庫(shimming)

在剛學Vue.js的時候,那時候運用的不是很熟,有時候須要操做DOM,可是Vue.js操做DOM很是的不方便;有時候須要獲取到 一個列表裏面全部的標籤,那時候就想到了使用Jquery來幫我操做DOM,當時就覺得像其它JS文件同樣全局導入就能夠了,可在實際運用的時候卻傻眼了,就發現,可以在控制檯輸出Jquery對象,可是卻沒法操做DOM,這讓我很抓狂。

通過學習,知道webpakc自己就已經提供了一套關於shimming解決方案:使用webpack內置的ProvidePlugin插件和expose-loader,在網上找了不少文檔,在使用webpack內置的ProvidePlugin插件的時候,雖然勉強解決這個問題,可是仍是有一些小問題,就eslint報錯的問題。後來發現使用expose-loader的方式也能夠解決這個問題。

webpack.ProvidePlugin

ProvidePluginwebpack內置插件,所以在使用前須要導入webpack,它主要的功能是:自動加載模塊,而沒必要處處 importrequire , 這也是webpack推薦的使用方法。

可是:對於 ES2015 模塊的 default export,你必須指定模塊的 default 屬性,由於它的名字;以jquery爲例: 它實際上就是 import $ from 'jquery',具體例子請看以下代碼。更多例子請戳這裏,查看官方示例說明。

const webpack = require('webpack')
/* 省略其它代碼 */
plugins: [
    new webpack.ProvidePlugin({
        $: 'jquery',  // 後面的jquery其實就是 import $ from 'jquery'
        JQuery: 'jquery'
    })
]

複製代碼

expose-loader

能夠經過expose-loaderwebpack注入一個全局的公共模塊,假設用了這個方法導入了jquery的話,是能夠全局使用,能夠理解成綁定到了window上,所以,在使用它的時候,須要下載這個expose-loader,以jquery爲例,使用方法以下:

module: {
  rules: [{
    test: require.resolve('jquery'), // 導入jquery模塊,但這個方法是node.js提供,和webpack無關
    use: [{
      loader: 'expose-loader', 
      options: 'jQuery' // 全局使用的名稱, window.jQuery
    },{
      loader: 'expose-loader',
      options: '$' // 全局使用名稱, window.$ 
    }]
  }]
}

複製代碼

可是這種方法,須要在局部導入(也就是說,須要每一個頁面都須要導入),而後才能進行全局暴露,可是若是須要全局注入的話,顯然這種方式不太穩當。

防止重複(SplitChunksPlugin)

webpack提供了一個Code Splitting拆分代碼,點擊這裏,能夠查看代碼分離的方式以及介紹。

使用CommonsChunkPlugin用於避免它們的重複依賴,可是沒法進一步優化;在webpack4的版本之後,刪除了optimization.splitChunks這個屬性;SplitChunksPlugin方法使用以下:

module.exports = {
    splitChunks: {
        chunks: "all",  // 同步和異步都作分割
        cacheGroups: { // 緩衝組
            vendors:false,
            default: false
        }
    }
}

複製代碼

SplitChunksPlugin的更多配置以下,具體參考官方說明,戳這裏點擊官方文檔

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'async', // async 默認推薦使用,異步加載作分割, initial 同步 all 同步和異步都作分割
      minSize: 30000, // 字節 引入的包或者模塊大於這個這個值,纔會作代碼分割,只針對同步加載
      maxSize: 0, // 超過 minSize 之後,會進行二次打包,默認不配置,不能強拆
      minChunks: 1, // 引入次數,引入次數爲多個,能夠打包
      maxAsyncRequests: 5, // 請求超過5個的部分不拆分,通常默認值
      maxInitialRequests: 3, // 頁面初始化同時發送的請求數量最大不能3個,超過之後就不會被拆分,默認值就會
      automaticNameDelimiter: '~', // 用以代碼分離打包的文件名默認鏈接符,cacheGroups裏面的vendors
      automaticNameMaxLength: 30, // 最長字節數,不能超過這個值
      name: true, // 拆分的名字, true表示根據模塊名和cacheGroups組的key來自動生成文件名
      cacheGroups: { // 緩存配置,一個文件import多個庫,若是須要多個庫打包成一個文件,則使用這個緩存組
        vendors: {
          test: /[\\/]node_modules[\\/]/, // 檢測引人的庫是不是node_modules下面的
          priority: -10, // 權重,決定哪一個組的優先配置
          name: "vendors" // 自定義名字,不須要後綴名
        },
        default: { // 前面沒有匹配上,則使用這個組,一般是業務代碼
          minChunks: 2, // 引入超過2次才重新打包成一個新文件
          priority: -20, // 權重
          reuseExistingChunk: true // 當爲true後就不會重複打包,會進行自動複用。
        }
      }
    }
  }
};

複製代碼

chunks的時候,還須要走cacheGroups緩衝組,分離出來的文件名是:cacheGroups裏面的vendors,中間的鏈接符是automaticNameDelimiter,例vendors-main.js

cacheGroups能夠自定義多個組,若是多個組都知足要求,則以權重大的組爲準。

webpack爲了更好的提高性能,最好的仍是使用異步的方式,這也是官方推薦。

Lazy Loding(動態導入懶加載)

當涉及到動態代碼拆分時,webpack 提供了兩個相似的技術。對於動態導入,第一種,也是優先選擇的方式是:ES7提出的一個草案,既import()語法。第二種,則是使用 webpack 特定的 require.ensure。先來講說第一種:

動態導入最大的好處就是實現了懶加載,用到那個模塊就纔會調用那個模塊,很是適合ASP導入,能夠大大的減小等待時間,但使用這個須要用到babel去轉,也就是須要下載@babel/plugin-syntax-dynamic-import這個插件,使用方法以下:

{
  "plugins": ["@babel/plugin-syntax-dynamic-import"] // 使用插件,在webpack plugins裏面添加
}

複製代碼

在頁面添加動態import導入懶加載的方式,這種方式會返回一個promise對象,代碼以下:

/* 聲明這個方法 須要一個函數 */ 
function getComponent() {
	import(/* webpackChunkName: "lodash" */ 'lodash').then( _ => {
            var element = document.createElement('div');
            element.innerHTML = _.join(['Hello', 'webpack'], ' ');
            return element;
		 }).catch( error => 'An error occurred while loading the component');
 }
/* 調用這個方法 若是不調用則不執行*/
getComponent().then(component => {
	document.body.appendChild(component);
})

複製代碼

這種方法,則會對代碼進行分離,將動態打入的第三方模塊,會單獨的打一個文件,而本身所寫的業務代碼,則會被打包到新的一個文件裏面。

/* webpackChunkName: "lodash" */ 'lodash'魔法字符串,懶加載,配合SplitChunksPlugin使用,能夠進行一個單獨配置,其實這個配置和SplitChunksPlugin是共用。

module.exports = {
    splitChunks: {
        cacheGroups: { // 緩衝組
            vendors: {
              test: /[\\/]node_modules[\\/]/, // 檢測引人的庫是不是node_modules下面的
              priority: -10, // 權重,決定哪一個組的優先配置
              name: "vendors" // 自定義名字,不須要後綴名
        	},
            default: false
        }
    }
}

複製代碼

可是使用懶加載的時候,會有一個弊端,就是當用戶須要一個模塊的時候,只有觸發之後,才能去加載對應的模塊,這就會形成一個網絡的延時,有一個等待期,不利於用戶體驗,因此就須要另一個技術,也就是預加載,當頁面自動加載出來之後,利用閒置的帶寬,去加載其它可能須要的模塊。

預加載(Prefetching)

這個是webpack 4.6.0新增的一個功能,用通俗的話來講,就是在網絡空閒的時候,纔去自動下載其它的非必要模塊,這種方式極大的提高了用戶體驗,也解決了等待延時問題,但是要怎麼使用呢?

/* 使用方法和上面的 懶加載是同樣的,只是這個魔法字符串裏面的參數不同 */
import(/* webpackPrefetch: true */ 'LoginModal');

複製代碼

在聲明導入時使用這些內聯指令容許webpack輸出「Resource Hint」,使用方法如上,它告訴瀏覽器:

  • prefetch:將來可能須要資源
  • preload:當前可能須要資源

區別:preload是和核心代碼一塊兒加載,prefetch預加載

緩存帶來的代碼提高是有限的,因此使用懶加載代碼優化是如今性能優化的主要使用方式。

webpack打包分析

關於打包分析,官網爲咱們提供了一個內置插件Bundle Analysis,在guider下面的Code Splitting裏面的Bundle Analysis,他有幾種類型,webpack-chart:(交互式餅圖)等類型,具體請戳這裏。使用方法也很簡單,只須要在package.json中配置一段腳本便可,例子以下:

scripts": {
	"build": "webpack  --profile --json > stats.json --env.production. --config build/webpack.base.conf.js"
}

複製代碼

其實也能夠直接使用webpack --profile --json > stats.json, 打包完成後,會生成一個stats.json文件,這個文件就是結果分析,而後須要將這個文件上傳到這個網站,進行數據分析,可是這個表,感受很是不人性化,我的以爲很難看,因此須要使用webpack-bundle-analyzer插件。

Webpack Bundle Analyzer也是一個打包分析,它和webpack-chart不一樣的是,Webpack Bundle Analyzer 是一個很直觀的平面圖,這是一個插件,因此在使用的時候,須要進行下載安裝,npm install --save-dev webpack-bundle-analyzer

若是使用了這個之後,在打包的時候,控制檯不會輸出打包信息,好比文件、 打包時間、chunk等信息,這也算是一個弊端。

在使用它的時候,也須要有如上的package.json中配置(實測,可不須要使用),在webpack裏面的基本配置以下,更多配置請戳這裏

// 導入插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// 使用它
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

複製代碼

CSS的代碼分離

它默認是打包在js文件裏面,這樣就會致使文件變得很大,因此將CSS代碼分離出來是頗有必要的,使用CSS代碼分析則須要使用一個插件來幫咱們完成,這個通常只作線上版本,在開發版本則不須要,這個插件的名字是MiniCssExtractPlugin,點擊這裏查看更多官方配置。

npm install --save-dev mini-css-extract-plugin  // 須要先安裝

複製代碼

簡單的配置說明,在使用的時候須要將style-loader替換爲MiniCssExtractPlugin.loader,若是須要在開發環境中使用熱更新,須要從新進行一個設置。

const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 導入插件
module.exports = {
  plugins: [
    new MiniCssExtractPlugin({ // 方法同output裏面的方法,最好就是加一個hash值,防止緩存
      filename: '[name].css',  // 生成的文件名
      chunkFilename: '[id].css', // 構建時生成,主要是防止文件更新瀏覽器不更新,緩存致使的
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader, // 替換style-loader
            options: { // 其它的配置項
              publicPath: '../', // 指定的地址,同等與output裏面的publicPath
              hmr: process.env.NODE_ENV === 'development', // 環境變量
            },
          },
          'css-loader',
        ],
      },
    ],
  },
};

複製代碼

CSS代碼分離,默認是不會被壓縮,若是想要代碼壓縮,則須要使用optimize-css-assets-webpack-plugin插件,但須要注意的是:設置optimization.minimizer會覆蓋webpack提供的默認值,所以須要指定,JS minimalizer, 使用方法以下:

const TerserJSPlugin = require('terser-webpack-plugin'); // 不添加則JS不會被壓縮
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 導入CSS分離插件
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // CSS代碼壓縮
module.exports = {
  optimization: { // 添加一個屬性,
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

複製代碼

設置optimization.minimizer會致使重寫,因此須要下載terser-webpack-plugin這個插件,去壓縮JS,若是沒有這個插件就會致使,CSS代碼被壓縮了,可是JS代碼則不會被壓縮。

配置模塊的解析方式(resolve)

Webpack 在啓動後會從配置的入口模塊出發找出全部依賴的模塊,Resolve 配置 Webpack 如何尋找模塊所對應的文件。 Webpack 內置 JavaScript 模塊化語法解析功能,默認會採用模塊化標準里約定好的規則去尋找,但你也能夠根據本身的須要修改默認的規則。

關於resolve的基本配置以下,更多配置戳這裏查看官方教程。

const path = require('path') // node提供的文件路徑模塊
module.exports = {
  resolve: {
    extensions: ['.wasm', '.mjs', '.js', '.json'],  // 自動解析肯定的擴展,能夠省略的擴展名
    alias: { //建立 import 或 require 的別名,來確保模塊引入變得更簡單。
        "@": path.resolve(__dirname, '../src'),
        xyz$: path.resolve(__dirname, 'XXX.js') // 精確匹配 xyz 
    }
  }
};

複製代碼

vue loader的使用

在搭建vue腳手架以前,須要下載兩個loader,分別是:vue-loadervue-template-compiler,具體的安裝方法查看Vue loader官方說明。

npm install -D vue-loader vue-template-compiler // 安裝

複製代碼

須要注意的問題:每一個 vue 包的新版本發佈時,一個相應版本的 vue-template-compiler 也會隨之發佈。編譯器的版本必須和基本的 vue 包保持同步,這樣 vue-loader 就會生成兼容運行時的代碼。這意味着你每次升級項目中的 vue 包時,也應該匹配升級 vue-template-compiler。

main.js中加入最基本的代碼,這也是最基本的入口配置信息

import Vue from 'vue'

window.vm = new Vue({
  el: '#app',
  render: h => h(App),
  components: { App },
  template: '<App/>'
})


複製代碼

正常來講,webpack在編譯的時候,是不認識.vue的後綴名,所以須要咱們手動的在webpack裏面新增一個loader,用於識別.vue文件,基本配置以下:

// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      // 它會應用到普通的 `.js` 文件
      // 以及 `.vue` 文件中的 `<script>` 塊
      {
        test: /\.js$/,
        loader: 'babel-loader'
      },
      // 它會應用到普通的 `.css` 文件
      // 以及 `.vue` 文件中的 `<style>` 塊
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    // 請確保引入這個插件來施展魔法
    new VueLoaderPlugin()
  ]
}
複製代碼

vue loader15+的版本都須要去使用一個vue-loader/lib/plugin插件,這個插件不用單獨下載,在使用vue-loader的時候,這個插件就已經有了。

webpack打包優化(DllPlugin)

爲了更快的使用打包優化,須要及時更新nodeJS以及webpack的版本,儘量的減小一些loader的轉換,而且須要剔除一些沒必要要的目錄,好比:node-modules的文件夾,插件儘量得時候使用官方推薦。 還可使用webpack內置的DllPlugin插件去幫咱們進行打包速度優化。

DllPlugin插件專門用於單獨的webpack配置中,以建立僅限dll的捆綁包。它建立了一個manifest.json文件,用於DllReferencePlugin映射依賴項(先建立一個,而後進行復制,這樣就提高了打包效率)。

更多的方法戳這裏查看官方教程,一般是建立一個webpack.dll.js文件,用來專門配置dllplugin,目的是爲了將一些公共的庫,打包成一個文件,後續打包不會從新打包,只會去引用打包好的包。

const path = require('path') // 導入node 模塊
module.exports = {
    mode: 'production', // 生產模式
    entry: {
        vendors: ['vue','jquery'] // 入口文件,自定義屬性
    },
    output:{
        filename: '[name].dll.js', // 輸出,多個文件打包成一個文件
        path: path.resolve(__dirname, '../dll'), // 打包的文件夾目錄
        library: '[name]' // 導出全局變量,用於其它文件
    }
}
複製代碼

可是這種方法,不會自動添加到html頁面中,所以須要一個插件add-asset-html-webpack-plugin,來幫我咱們將webpack.dll.js打包後文件自動添加到html中,關於更多說明戳這裏查看NPM教程

cnpm i add-asset-html-webpack-plugin -D  // 安裝
複製代碼

使用它的時候,此時就不能寫在webpack.dll.js文件中,應該寫在公共的文件當中,好比webpack.base.conf.js文件裏面,基本配置方法以下:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 導入自動生成html插件
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin'); // 自動添加插件
const webpackConfig = {
  entry: 'index.js',
  output: {
    path: 'dist',
    filename: 'index_bundle.js',
  },
  plugins: [
    new HtmlWebpackPlugin(),// 更多說明請看前面的 HtmlWebpackPlugin 配置
     // require.resolve和 path.resolve, 在這裏的用法是同樣的,
    new AddAssetHtmlPlugin({ filepath: require.resolve('../dll/vendors.dll.js') }),
  ],
};
複製代碼
相關文章
相關標籤/搜索