遵循不重复原则(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