遵循不重複原則(DRY)vue
webpack 的相關配置須要保留一個 common配置、一個dev配置、一個prod配置node
經過
webpack-merge
包將其整合jquery
開發環境時 一些工具的使用是沒有意義的,好比 壓縮代碼、文件名哈希、分離代碼等...webpack
項目中 安裝、配置以下es6
npm i webpack-merge@4.1.5 -D
複製代碼
// webpack/webpack.common.js
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Production'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
複製代碼
// webpack/webpack.dev.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
devtool: 'inline-source-map',
devServer: {
contentBase: './dist'
}
});
複製代碼
// webpack/webpack.prod.js
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
plugins: [
new UglifyJSPlugin()
]
});
複製代碼
// package.json 配置 npm script
{
"scripts": {
"start": "webpack-dev-server --open --config webpack/webpack.dev.js",
"build": "webpack --config webpack/webpack.prod.js"
}
}
複製代碼
source map 反應資源的映射關係,用於 定位代碼中的錯誤web
開發環境下 建議正則表達式
{
devtool: "cheap-module-eval-source-map"
}
複製代碼
生產環境下 建議
{
devtool: false
}
複製代碼
做用:
符合以下條件,自動開啓 Tree Shaking:
webpack 4.X 生產模式下
編碼時,遵循 ES6 模塊化語法(require
無效)
編譯時,不要編譯 ES6模塊
// .babelrc 配置以下
{
"presets": [
[
"@babel/preset-env",
{
"modules": false
}
]
]
}
複製代碼
生產模式下 ES6 模塊化語法 實踐:
實踐一:
// a.js 文件
const dict = 'dict';
const dictMedia = 'dictMedia';
export default {
dict,
dictMedia
};
複製代碼
// 引入 a.js 文件
import dicts from '/a';
console.log(dicts);
// a.js 文件中的 dict、dictMedia 都被打包
複製代碼
實踐二:
// a.js 文件
const dict = 'dict';
const dictMedia = 'dictMedia';
export default {
dict,
dictMedia
};
複製代碼
// 引入 a.js 文件
import dicts from '/a';
console.log(dicts.dict);
// a.js 文件中的 dict 被打包;dictMedia 不被打包
複製代碼
實踐三:
// a.js 文件
const dict = 'dict';
const dictMedia = 'dictMedia';
export {
dict,
dictMedia
};
複製代碼
// 引入 a.js 文件
import {dict, dictMedia} from '/a';
console.log(dict, dictMedia);
// a.js 文件中的 dict 被打包;dictMedia 不被打包
複製代碼
實踐四:
// a.js 文件
const dict = 'dict';
const dictMedia = 'dictMedia';
export {
dict,
dictMedia
};
複製代碼
// 引入 a.js 文件
import {dict} from '/a';
console.log(dict);
// a.js 文件中的 dict 被打包;dictMedia 不被打包
複製代碼
概述
Scope Hoisting 可讓webpack打包出來的代碼文件更小、運行更快
webpack4 的生產模式,默認開啓 Scope Hoisting
webpack3 推出的功能,須要手動開啓 粗略講解 在此
原理:
分析出模塊之間的依賴關係,儘量的把打散的模塊合併到一個函數中去
前提是不能形成代碼冗餘
是否開啓 Scope Hoisting 的對比
// util.js 文件
export default 'Hello,Webpack';
複製代碼
// main.js 入口文件
import str from './util.js';
console.log(str);
複製代碼
// 未開啓 Scope Hoisting 打包後以下
[
(function (module, __webpack_exports__, __webpack_require__) {
var __WEBPACK_IMPORTED_MODULE_0__util_js__ = __webpack_require__(1);
console.log(__WEBPACK_IMPORTED_MODULE_0__util_js__["a"]);
}),
(function (module, __webpack_exports__, __webpack_require__) {
__webpack_exports__["a"] = ('Hello,Webpack');
})
]
複製代碼
// 開啓 Scope Hoisting 打包後以下
[
(function (module, __webpack_exports__, __webpack_require__) {
var util = ('Hello,Webpack');
console.log(util);
})
]
複製代碼
全稱:Hot Module Replacement
應用場景:開發環境下
做用:熱替換 HMR,在啓動開發服務時,局部加載 頁面被修改之處;加快開發編譯速度
保留在徹底從新加載頁面時丟失的應用程序狀態
只更新變動內容,以節省寶貴的開發時間
調整樣式更加快速:幾乎至關於在瀏覽器調試器中更改樣式
限制:HMR 是可選功能(只會影響包含 HMR 代碼的模塊)
舉個例子,經過 style-loader 爲 style 樣式追加補丁。爲了運行追加補丁,style-loader 實現了 HMR 接口;當它經過 HMR 接收到更新,它會使用新的樣式替換舊的樣式
若是一個模塊沒有 HMR 處理函數,更新就會冒泡(bubble up)。這意味着一個簡單的處理函數可以對整個模塊樹(complete module tree)進行更新
配置 HMR
// webpack 配置文件中
const webpack = require('webpack');
module.exports = {
devServer: {
contentBase: path.resolve(__dirname,'dist'),
compress: true,
host: 'localhost',
port:3000,
hot: true // 開啓 熱替換
},
plugins: [
new webpack.NamedModulesPlugin(), // 必要的配置
new webpack.HotModuleReplacementPlugin() // 必要的配置
]
};
複製代碼
方式一:使用 ES6 的模塊化語法,動態加載模塊 import()
import('') 語法目前只是 ECMAScript 提案階段,還沒被正式發佈
// .babelrc 中
// babel 7
{
"plugins": [
"@babel/plugin-syntax-dynamic-import"
]
}
複製代碼
方式二:使用 webpack 對代碼進行分割,按需加載(webpack 的 require.ensure
語法)
require.ensure
是 webpack 語法:
參數1:要依賴的模塊;類型爲 字符串數組;通常爲空
參數2:加載依賴後,自動執行的回調函數
參數3:打包後,js 文件的輸出路徑、js 文件名(chunk名稱)
const router = new VueRouter({
routes: [ // 定義路由信息對象
{
path: string,
name?: string,
component: (resolve) => {
require.ensure([], () => {
resolve(require('../../view/demo/index.vue'))
}, 'demo')
}
}
]
});
複製代碼
做用:配置 loader 的生效範圍,可提升編譯速度
以配置 babel-loader
爲例
// 不推薦
// webpack配置文件中 配置
const path = require('path');
module: {
rules: [{
test: /\.js$/,
use: ['babel-loader']
}]
}
複製代碼
// 推薦
// webpack配置文件中 配置
const path = require('path');
module: {
rules: [{
test: /\.js$/,
use: ['babel-loader'],
exclude: '', // 排除不要加載的文件夾
include: [path.resolve(__dirname, 'src'), /node_modules/] // 指定須要加載的文件夾
}]
}
複製代碼
exclude
、 include
的值:
值能夠是單獨項、能夠是數組
能夠是路徑、能夠是正則
項目實戰:
項目開發中,針對主要 lodaer 如
babel-loader
、style-loader
、sass-lodaer
等
配置生效範圍: 除了要轉換項目代碼,還要轉換
node_modules
中代碼;不然 針對沒有徹底轉成JS的node包,會報錯
resolve
給模塊起別名:resolve.alias
// webpack 配置
module.exports = {
//...
resolve: {
alias: {
'@components': '/src/common'
}
}
};
複製代碼
// 項目代碼
import a from '@components/utils';
// 等同於
import a from '/src/common/utils';
複製代碼
自動添加後綴 規則:resolve.extensions
當引入模塊時不帶文件後綴,webpack 會根據配置依次添加後綴 尋找文件
// webpack 配置
module.exports = {
//...
resolve: {
extensions: ['.vue', '.js', '.scss', '.css', '.json']
}
};
複製代碼
解析目錄時要使用的文件名:resolve.mainFiles
默認尋找
index
命名的文件
// webpack 配置
module.exports = {
//...
resolve: {
mainFiles: ["index"]
}
};
複製代碼
指明第三方模塊存放的位置,以減小搜索步驟
默認值:[node modules]
默認搜索步驟:先去當前目錄的 /node modules
目錄下去找咱們想找的模塊,若是沒找到,就去上一級目錄 ../node modules
中找,再沒有就去 ../../node modules
中找
// webpack 配置
module.exports = {
//...
resolve: {
modules: [path.resolve(__dirname, 'node_modules')]
}
};
複製代碼
引入的模塊,尋找規則:
不建議寫文件後綴名,就意味着引入的模塊路徑,路徑最後一層有多是文件;有多是文件夾
默認將路徑的最後一層 視爲文件名,依次匹配 配置的後綴名
若是沒找到該文件,將路徑的最後一層視爲文件夾,依次匹配 設置的文件名,找到後再 依次匹配設置的後綴名
如都沒找到,就會報錯
場景:
一些沒有采用模塊化的文件,沒有必要讓 webpack 進行處理編譯
經過配置 modules.noParse
,可讓 webpack 忽略,提高編譯速度
配置:
module.exports = merge(common, {
modules: {
// 使用正則表達式
noParse: /jquery|chartjs/
// 或
// 使用函數,從 Webpack 3.0.0 開始支持
noParse: (content)=> {
// content 表明一個模塊的文件路徑
// 返回 true or false
return /jquery|chartjs/.test(content);
}
}
});
複製代碼
webpack 打包後,若是文件體積超出默認(250kb)大小,會輸出警告
開發環境下這是一個不錯的提示,但生產環境下徹底不必,能夠經過 performance
進行相關配置
配置以下
// webpack 配置
module.exports = merge(common, {
performance: {
hints: false, // 關閉警告
maxEntrypointSize: 400000 // 預警值設置成40kb
}
});
複製代碼
場景:項目開發過程當中,配置 每一個文件中均可以使用的 JS 變量
直接獲取 開發環境變量 process.env.NODE_ENV
使用webpack4.x,webpack 會將環境變量
process.env.NODE_ENV
的值,設置爲 webpack配置中 mode 的值
在項目代碼中 能夠直接使用
process.env.NODE_ENV
// 項目代碼中
console.log(process.env.NODE_ENV); // development
複製代碼
設置 / 獲取 新的環境變量
使用 webpack 的內置插件 DefinePlugin,能夠爲項目代碼定義環境變量
限制:DefinePlugin 設置的環境變量只能在項目代碼中獲取,不能再 webpack 的配置文件中獲取
// webpack 配置以下
const webpack = require('webpack');
module.exports = merge(common, {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('ddd'), // 覆蓋 process.env.NODE_ENV
'process.env.globalName': JSON.stringify('globalName'),
'globalName': JSON.stringify('eeee'),
})
]
});
複製代碼
// 項目代碼中
console.log(process.env.NODE_ENV); // ddd
console.log(process.env.globalName); // globalName
console.log(globalName); // eeee
複製代碼
場景:配置webpack時,可能須要經過 npm script 傳參,用來處理不一樣場景下的不一樣需求
方式一:不一樣系統存在 兼容問題
在腳本命令的配置(package.json 的 script
下) 中傳參(window)
// window 系統下:傳參
"scripts": {
"server": "webpack-dev-server --open",
"build:dev":"set type=dev&webapck",
"build:prod": "set type=prod&webpack"
},
複製代碼
在腳本命令的配置(package.json 的 script
下) 中傳參(mac)
// mac 系統下:傳參
"scripts": {
"server": "webpack-dev-server --open",
"build:dev":"export type=dev&&webpack",
"build:prod": "export type=prod&&webpack"
},
複製代碼
接收參數
// node的語法來讀取type的值,而後根據type的值用if–else判斷
if(process.env.type== "build"){
// 生產環境
var website={
publicPath:"http://192.168.0.104:1717/"
}
}else{
// 開發環境
var website={
publicPath:"http://cdn.jspang.com/"
}
}
複製代碼
方式二:要求 webpack 配置項輸入函數(無系統兼容問題)
在腳本命令的配置(package.json 的 script
下) 中傳參
// package.json 以下
{
"scripts": {
"build": "webpack --env.NODE_ENV=local --env.production --progress"
},
}
複製代碼
webpack 配置文件中 獲取環境變量
必須對 webpack 配置進行一處修改。一般,module.exports 指向配置對象;要使用 env 變量,你必須將 module.exports 轉換成一個函數
module.exports = env => {
console.log('NODE_ENV: ', env.NODE_ENV) // 'local'
console.log('Production: ', env.production) // true
return {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
}
};
複製代碼
執行命令 npm run build
,便可在控制檯中 看到輸出的 環境變量的值
這樣就能夠在 webpack 中經過區分不一樣的環境變量,來配置不一樣的webpack
方式三:無系統兼容問題,無過多要求
在腳本命令的配置(package.json 的 script
下) 中傳參
// package.json 以下
{
"scripts": {
"build": "webpack --prod"
},
}
複製代碼
webpack 配置文件中 獲取參數以下
// webpack 配置文件中
console.log(process.argv);
// 輸出 [ node 路徑, webpack 路徑, '--prod']
複製代碼
若是隻是想傳遞一個布爾值,獲取參數以下
// 安裝 minimist
npm i minimist@1.2.0 -D
複製代碼
// webpack 配置文件中
const processArgv = require('minimist')(process.argv.slice(2));
console.log(processArgv.prod); // true
複製代碼
小夥伴們,有什麼問題 能夠留言,一塊兒交流哈
接下來,我還會發布幾篇 webpack4.X 實戰文章,敬請關注
我是一名熱衷於編程的前端開發,WX:ZXvictory66