經過排除node_modules下的文件 從而縮小了loader加載搜索範圍 高几率命中文件html
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader',
exclude: /node_modules/, // 排除不處理的目錄
include: path.resolve(__dirname, 'src') // 精確指定要處理的目錄
}
]
}
複製代碼
cacheDirectory是loader的一個特定的選項,默認值是false。指定的目錄(use: 'babel-loader?cacheDirectory=cacheLoader')將用來緩存loader的執行結果,減小webpack構建時Babel從新編譯過程。若是設置一個空值(use: 'babel-loader?cacheDirectory') 或true(use: 'babel-loader?cacheDirectory=true') 將使用默認的緩存目錄(node_modules/.cache/babel-loader),若是在任何根目錄下都沒有找到 node_modules 目錄,將會降級回退到操做系統默認的臨時文件目錄。前端
webpack4官方文檔 babel-loader很慢!vue
module: {
rules: [
{
test: /\.js$/,
use: 'babel-loader?cacheDirectory', // 緩存loader執行結果 發現打包速度已經明顯提高了
exclude: /node_modules/,
include: path.resolve(__dirname, 'src')
}
]
}
複製代碼
Webpack的resolve.modules配置模塊庫(即 node_modules)所在的位置,在 js 裏出現 import 'vue' 這樣不是相對、也不是絕對路徑的寫法時,會去 node_modules 目錄下找。可是默認的配置,會採用向上遞歸搜索的方式去尋找,但一般項目目錄裏只有一個 node_modules,且是在項目根目錄,爲了減小搜索範圍,能夠直接寫明 node_modules 的全路徑;一樣,對於別名(alias)的配置,亦當如此:node
const path = require('path');
function resolve(dir) { // 轉換爲絕對路徑
return path.join(__dirname, dir);
}
resolve: {
modules: [ // 優化模塊查找路徑
path.resolve('src'),
path.resolve('node_modules') // 指定node_modules所在位置 當你import 第三方模塊時 直接從這個路徑下搜索尋找
]
}
複製代碼
配置好src目錄所在位置後,因爲util目錄是在src裏面 因此能夠用下面方式引入util中的工具函數react
// main.js
import dep1 from 'util/dep1';
import add from 'util/add';
複製代碼
建立 import 或 require 的路徑別名,來確保模塊引入變得更簡單。配置項經過別名來把原導入路徑映射成一個新的導入路徑 此優化方法會影響使用Tree-Shaking去除無效代碼jquery
例如,一些位於 src/ 文件夾下的經常使用模塊:webpack
alias: {
Utilities: path.resolve(__dirname, 'src/utilities/'),
Templates: path.resolve(__dirname, 'src/templates/')
}
複製代碼
如今,替換「在導入時使用相對路徑」這種方式,就像這樣:git
import Utility from '../../utilities/utility';
複製代碼
你能夠這樣使用別名:es6
import Utility from 'Utilities/utility';
複製代碼
resolve: {
alias: { // 別名配置 經過別名配置 可讓咱們引用變的簡單
'vue$': 'vue/dist/vue.common.js', // $表示精確匹配
src: resolve('src') // 當你在任何須要導入src下面的文件時能夠 import moduleA from 'src/moduleA' src會被替換爲resolve('src') 返回的絕對路徑 而不須要相對路徑形式導入
}
}
複製代碼
也能夠在給定對象的鍵後的末尾添加 $,以表示精準匹配:
alias: {
util$: resolve('src/util/add.js')
}
複製代碼
這將產生如下結果:
import Test1 from 'util'; // 精確匹配,因此 src/util/add.js 被解析和導入
import Test2 from 'util/dep1.js'; // 精確匹配,觸發普通解析 util/dep1.js
複製代碼
當引入模塊時不帶文件後綴 webpack會根據此配置自動解析肯定的文件後綴
resolve: {
extensions: ['.js', '.vue']
}
複製代碼
用了noParse的模塊將不會被loaders解析,因此當咱們使用的庫若是太大,而且其中不包含import require、define的調用,咱們就可使用這項配置來提高性能, 讓 Webpack 忽略對部分沒采用模塊化的文件的遞歸解析處理。
// 忽略對jquery lodash的進行遞歸解析
module: {
// noParse: /jquery|lodash/
// 從 webpack 3.0.0 開始
noParse: function(content) {
return /jquery|lodash/.test(content)
}
}
複製代碼
HappyPack是讓webpack對loader的執行過程,從單一進程形式擴展爲多進程模式,也就是將任務分解給多個子進程去併發的執行,子進程處理完後再把結果發送給主進程。從而加速代碼構建 與 DLL動態連接庫結合來使用更佳。
npm i happypack@next -D
複製代碼
webpack.config.js
const HappyPack = require('happypack');
const os = require('os'); // node 提供的系統操做模塊
// 根據個人系統的內核數量 指定線程池個數 也能夠其餘數量
const happyThreadPool = HappyPack.ThreadPool({size: os.cpus().length})
module: {
rules: [
{
test: /\.js$/,
use: 'happypack/loader?id=babel',
exclude: /node_modules/,
include: path.resolve(__dirname, 'src')
}
]
},
plugins: [
new HappyPack({ // 基礎參數設置
id: 'babel', // 上面loader?後面指定的id
loaders: ['babel-loader?cacheDirectory'], // 實際匹配處理的loader
threadPool: happyThreadPool,
// cache: true // 已被棄用
verbose: true
});
]
複製代碼
happypack提供的loader,是對文件實際匹配的處理loader。這裏happypack提供的loader與plugin的銜接匹配,則是經過id=happypack來完成。 資料:happypack原理解析-淘寶前端
npm run dev
複製代碼
在一個動態連接庫中能夠包含其餘模塊調用的函數和數據,動態連接庫只需被編譯一次,在以後的構建過程當中被動態連接庫包含的模塊將不會被從新編譯,而是直接使用動態連接庫中的代碼。
5.1 定義DLL配置
依賴的兩個內置插件:DllPlugin 和 DllReferencePlugin
5.1.1 建立一個DLL配置文件webpack_dll.config.js
module.exports = {
entry: {
react: ['react', 'react-dom']
},
output: {
filename: '[name].dll.js', // 動態連接庫輸出的文件名稱
path: path.join(__dirname, 'dist'), // 動態連接庫輸出路徑
libraryTarget: 'var', // 連接庫(react.dll.js)輸出方式 默認'var'形式賦給變量 b
library: '_dll_[name]_[hash]' // 全局變量名稱 導出庫將被以var的形式賦給這個全局變量 經過這個變量獲取到裏面模塊
},
plugins: [
new webpack.DllPlugin({
// path 指定manifest文件的輸出路徑
path: path.join(__dirname, 'dist', '[name].manifest.json'),
name: '_dll_[name]_[hash]', // 和library 一致,輸出的manifest.json中的name值
})
]
}
複製代碼
5.1.2 output.libraryTarget 規定了以哪種導出你的庫 默認以全局變量形式 瀏覽器支持的形式
具體包括以下:
"var" - 以直接變量輸出(默認library方式) var Library = xxx (default)
"this" - 經過設置this的屬性輸出 this["Library"] = xxx
"commonjs" - 經過設置exports的屬性輸出 exports["Library"] = xxx
"commonjs2" - 經過設置module.exports的屬性輸出 module.exports = xxx
"amd" - 以amd方式輸出
"umd" - 結合commonjs2/amd/root
5.1.3 打包生成動態連接庫
webpack --config webpack_dll.config.js --mode production
複製代碼
5.2 在主配置文件中使用動態連接庫文件
// webpack.config.js
const webpack = require('webpack');
plugins: [
// 當咱們須要使用動態連接庫時 首先會找到manifest文件 獲得name值記錄的全局變量名稱 而後找到動態連接庫文件 進行加載
new webpack.DllReferencePlugin({
manifest: require('./dist/react.manifest.json')
})
]
複製代碼
5.3 將動態連接庫文件加載到頁面中
須要藉助兩個webpack插件
npm i html-webpack-plugin html-webpack-include-assets-plugin -D
複製代碼
配置webpack.config.js
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const HtmlIncludeAssetsPlugin = require('html-webpack-include-assets-plugin');
pluings: [
new webpack.DllReferencePlugin({
manifest: require('./dist/react.manifest.json')
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src/index.html')
}),
new HtmlIncludeAssetsPlugin({
assets: ['./react.dll.js'], // 添加的資源相對html的路徑
append: false // false 在其餘資源的以前添加 true 在其餘資源以後添加
});
]
複製代碼
此時react.dll.js和main.js被自動引入到頁面中,而且dll文件在main.js以前加載
這個插件能夠幫助有不少入口點的項目加快構建速度。把對JS文件的串行壓縮變爲開啓多個子進程並行進行uglify。
cnpm i webpack-parallel-uglify-plugin -D
複製代碼
// webpck.config.js
const ParallelUglifyPlugin = require('webpack-parallel-uglify-plugin');
plugins: [
new ParallelUglifyPlugin({
workerCount: 4,
uglifyJS: {
output: {
beautify: false, // 不須要格式化
comments: false // 保留註釋
},
compress: { // 壓縮
warnings: false, // 刪除無用代碼時不輸出警告
drop_console: true, // 刪除console語句
collapse_vars: true, // 內嵌定義了可是隻有用到一次的變量
reduce_vars: true // 提取出出現屢次可是沒有定義成變量去引用的靜態值
}
}
});
]
複製代碼
執行壓縮
webpack --mode production
複製代碼
剔除JavaScript中用不上的代碼。它依賴靜態的ES6模塊化語法,例如經過impot和export導入導出
commonJS模塊:
1.動態加載模塊 commonJS 是運行時加載 可以輕鬆實現懶加載,優化用戶體驗
2.加載整個模塊 commonJS模塊中,導出的是整個模塊
3.每一個模塊皆爲對象 commonJS模塊被視做一個對象
4.值拷貝 commonJS的模塊輸出和函數的值傳遞類似,都是值得拷貝
es6模塊
1.靜態解析 es6模塊時 編譯時加載 即在解析階段就肯定輸出的模塊的依賴關係,因此es6模塊的import通常寫在被引入文件的開頭
2.模塊不是對象 在es6裏,每一個模塊並不會當作一個對象看待
3.加載的不是整個模塊 在es6模塊中 一個模塊中有好幾個export導出
4.模塊的引用 es6模塊中,導出的並非模塊的值得拷貝,而是這個模塊的引用
7.1 保留ES6模塊化語法
// .babelrc
{
"presets": [
[
"env", {
modules: false // 不要編譯ES6模塊
},
"react",
"stage-0"
]
]
}
複製代碼
7.2 執行生產編譯 默認已開啓Tree Shaking
webpack --mode production
複製代碼
有個funs.js 裏面有兩個函數
// funs.js
export const sub = () => 'hello webpack!';
export const mul = () => 'hello shaking!';
複製代碼
main.js 中依賴funs.js
// main.js
import {sub} from './funs.js'
sub();
複製代碼
在main.js只使用了裏面的 sub函數 默認狀況下也會將funs.js裏面其餘沒有的函數也打包進來, 若是開啓tree shaking 生產編譯時
webpack --mode production //此時funs.js中沒有被用到的代碼並沒打包進來 而被剔除出去了
複製代碼