Webpack4
webpack开篇
什么是webpack
webpack是一套基于
NodeJS
的"模块打包工具",在webpack刚推出的时候就是一个单纯的JS模块打包工具,可以将多个模块的JS文件合并打包到一个文件中,但是随着时间的推移、众多开发者的追捧和众多开发者的贡献,现在webpack不仅仅能够打包JS模块
, 还可以打包CSS/LESS/SCSS/
图片
等其它文件;
为什么要分模块
如果将所有的JS代码都写到一个文件中, 十分不利于代码的维护和复用,所以我们可以将不同的功能写到不同的模块中, 这样就提升了代码的维护性和复用性,但是当将代码写到不同模块时新的问题又出现了;
例如
- 导入资源变多了, 请求次数变多了, 网页性能也就差了;
例如
- 不同功能都放到了不同模块中了, 那么如何维护模块之间的关系也变成一个难题了;
<script src="./header.js"></script>
<script src="./content.js"></script>
<script src="./index.js"></script>
<script src="./footer.js"></script> // 如果index.js中用到了footer,就会报错
例如
... ...
如何解决上述问题
-
项目上线时将用到的所有模块都合并到一个文件中;
-
在index.html中只导入主文件, 再主文件中再导入依赖模块;
如何通过webpack来打包JS模块
- 安装webpack
npm init -y
npm install --save-dev webpack
npm install --save-dev webpack-cli
- 在终端中输入打包的指令
npx webpack index.js
注意点
- index.js就是需要打包的文件;
- 打包之后的文件会放到
dist
目录中, 名称叫做main.js
;
webpack配置文件
什么是webpack配置文件?
- 我们在打包JS文件的时候需要输入:
npx webpack index.js
- 这句指令的含义是: 利用 webpack 将 index.js 和它依赖的模块打包到一个文件中
- 其实在 webpack 指令中除了可以通过命令行的方式告诉 webpack 需要打包哪个文件以外
- 还可以通过配置文件的方式告诉 webpack 需要打包哪个文件
webpack常见配置
属性名 | 作用 |
---|---|
entry | 需要打包的文件 |
output | 打包之后输出路径和文件名称 |
mode | 打包模式 development/production |
development | 不会压缩打包后的JS代码 |
production | 会自动压缩打包后的JS代码 |
webpack.config.js
const path = require("path");
module.exports = {
/*
mode: 指定打包的模式, 模式有两种
一种是开发模式(development): 不会对打包的JS代码进行压缩
还有一种就是上线(生产)模式(production): 会对打包的JS代码进行压缩
* */
mode: "development", // "production" | "development"
/*
entry: 指定需要打包的文件
* */
entry: "./index.js",
/*
output: 指定打包之后的文件输出的路径和输出的文件名称
* */
output: {
/*
filename: 指定打包之后的JS文件的名称
* */
filename: "bundle.js",
/*
path: 指定打包之后的文件存储到什么地方
* */
path: path.resolve(__dirname, "bundle")
}
};
webpack配置文件注意点
webpack配置注意事项
- 配置文件的名称必须叫做:
webpack.config.js
, 否则直接输入npx webpack
打包会出错 - 如果要使用其它名称, 那么在输入打包命令时候必须通过
--config 指定配置文件名称
npx webpack --config xxx
打包命令简化
- 每次输入
npx webpack --config xxx
来打包文件会有一点蛋疼, 所以我们可以通过npm script
来简化这个操作
webpack-sourcemap
什么是sourcemap?
- webpack 打包后的文件会自动添加很多代码, 在开发过程中非常不利于我们去调试
- 因为如果运行 webpack 打包后的代码,错误提示的内容也是打包后文件的内容
- 所以为了降低调试的难度, 提高错误代码的阅读性, 我们就需要知道打包后代码和打包之前代码的映射关系
- 只要有了这个映射关系我们就能很好的显示错误提示的内容, 存储这个映射关系的文件我们就称之为
sourcemap
如何开启sourcemap
- 文档: https://www.webpackjs.com/configuration/devtool/
- 在
webpack.config.js
中添加devtool: "xxx"
- 各配置项说明
属性名 | 作用 | 优势 | 缺点 |
---|---|---|---|
eval | 不会单独生成 sourcemap 文件, 会将映射关系存储到打包的文件中, 并且通过 eval 存储 |
性能最好 | 业务逻辑比较复杂时候提示信息可能不全面不正确 |
source-map | 会单独生成 sourcemap 文件, 通过单独文件来存储映射关系 |
提示信息全面,可以直接定位到错误代码的行和列 | 打包速度慢 |
inline | 不会单独生成 sourcemap 文件, 会将映射关系存储到打包的文件中, 并且通过 base64 字符串形式存储 |
||
cheap | 生成的映射信息只能定位到错误行不能定位到错误列 | ||
module | 不仅希望存储我们代码的映射关系, 还希望存储第三方模块映射关系, 以便于第三方模块出错时也能更好的排错 |
企业开发配置
属性名 | 作用 |
---|---|
development: cheap-module-eval-source-map | 只需要行错误信息, 并且包含第三方模块错误信息, 并且不会生成单独sourcemap 文件 |
production: cheap-module-source-map | 只需要行错误信息, 并且包含第三方模块错误信息, 并且会生成单独sourcemap 文件 |
webpack-file-loader
什么是loader?
- webapck 的本质是一个模块打包工具, 所以 webpack 默认只能处理 JS 文件,不能处理其他文件
- 因为其他文件中没有模块的概念, 但是在企业开发中我们除了需要对 JS 进行打包以外
- 还有可能需要对 图片/CSS 等进行打包, 所以为了能够让 webpack 能够对其它的文件类型进行打包
- 在打包之前就必须将其它类型文件转换为 webpack 能够识别处理的模块
- 用于将其它类型文件转换为 webpack 能够识别处理模块的工具我们就称之为 loader
如何使用loader
- webpack 中的 loader 都是用 NodeJS 编写的, 但是在企业开发中我们完全没有必要自己编写
- 因为已经有众多大神帮我们编写好了企业中常用的 loader , 我们只需要安装、配置、使用即可
通过npm安装对应的loader
- 按照 loader 作者的要求在 webpack 进行相关配置
- 使用配置好的 loader
fileloader使用
安装file-loader
npm install --save-dev file-loader
在 webpack.config.js 中配置 file-loader
module: {
rules: [
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'file-loader',
options: {}
}
]
}
]
}
webpack-file-loader 其它配置
注意点
-
默认情况下 fileloader 生成的图片名就是文件内容的
MD5
哈希值 -
如何想打包后不修改图片的名称, 那么可以新增配置
name: "[name].[ext]"
-
其它命名规则详见:
placeholders
-
默认情况下 fileloader 会将生成的图片放到
dist
根目录下面 -
如果想打包之后放到指定目录下面, 那么可以新增配置
outputPath: "images/"
-
如果需要将图片托管到其它服务器, 那么只需在打包之前配置
publicPath: "托管服务器地址"
即可
webpack-url-loader
url loader
- url-loader 功能类似于 file-loader
- 但是在文件大小(单位 byte)低于指定的限制时,可以返回一个
DataURL
url loader 使用
url loader 安装
npm install --save-dev url-loader
url loader 配置
{
test: /\.(png|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
name: "[name].[ext]",
outputPath: "/images",
limit: 1024
}
}
]
}
url loader 优势
- 图片比较小的时候直接转换成
base64
字符串图片, 减少请求次数 - 图片比较大的时候由于生成的
base64
字符串图片也比较大, 就保持原有的图片
webpack-css-loader
css-loader
和图片一样 webpack 默认能不能处理 CSS 文件, 所以也需要借助 loader 将 CSS 文件转换为 webpack 能够处理的类型。
css-loader 使用
① 安装 css-loader
npm install --save-dev css-loader
② 安装 style-loader
npm install style-loader --save-dev
③ 配置 css-loader
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}
css-loader 和 style-loader 作用
loaderName | 作用 |
---|---|
css-loader | 解析 css 文件中的 @import 依赖关系 |
style-loader | 将 webpack 处理之后的内容插入到 HTML 的 HEAD 代码中 |
css-loader 注意点
- loader 特点
- 单一原则, 一个 loader 只做一件事情
- 多个 loader 会按照从
右
至左
, 从下
至上
的顺序执行
- 例如:从右至左
- [ 'style-loader', 'css-loader' ]
- 先执行 css-loader 解析 css 文件关系拿到所有内容
- 再执行 style-loader 将内容插入到 HTML 的 HEAD 代码中
- 例如: 从下至上
- [{
loader: "style-loader"
},{
loader: "css-loader"
}] - 先执行 css-loader 解析 css 文件关系拿到所有内容
- 再执行 style-loader 将内容插入到 HTML 的 HEAD 代码中
- [{
ES6-Module
ES6 模块化
- 在 ES6 出现之前,JS 不像其他语言拥有
模块化
这一概念,于是为了支持 JS 模块化 - 我们使用类、立即执行函数或者第三方插件 (RequireJS、seaJS) 来实现模块化
- 但是在 ES6 出现之后, 上述解决方案都已经被废弃, 因为 ES6 中正式引入了模块化的概念
- ES6 模块化模块和 NodeJS中一样, 一个文件就是一个模块, 模块中的数据都是私有的
- ES6 模块化模块和 NodeJS 中一样, 可以通过对应的关键字暴露模块中的数据,可以通过对应的关键字导入模块, 使用模块中暴露的数据
ES6 模块化使用
- 常规导出
- 分开 导入 导出
export xxx;
import {xxx} from "path";
- 一次性 导入 导出
export {xxx, yyy, zzz};
import {xxx, yyy, zzz} from "path";
- 注意点
- 接收 导入变量名 必须和 导出变量名 一致
- 如果想修改 接收变量名 可以通过
xxx as newName
方式 - 变量名 被修改后原有 变量名 自动失效
- 默认 导入 导出
export default xxx;
import xxx from "path";
- 注意点
- 一个 模块 只能 使用一次 默认 导出, 多次 无效
- 默认 导出时, 导入的名称 可以和 导出的名称 不一致
- 示例
/*
ES6模块化的第一种方式
导出数据: export {xxx};
导入数据: import {xxx} from "path";
* */
/*
注意点:
1.如果是通过export {xxx};方式导出数据, 那么在导入接收的时候接收的变量名称必须和导出的名称一致
究其原因是因为在导入的时候本质上是ES6的解构赋值
2.如果是通过export {xxx};方式导出数据, 又想在导入数据的时候修改接收的变量名称, 那么可以使用as来修改
但是如果通过as修改了接收的变量名称, 那么原有的变量名称就会失效
* */
/*
// import {name} from "./a.js";
import {str} from "./a.js";
console.log(str);
*/
/*
let obj = {
name: "xhh",
age: 18
};
// let {name, age} = obj;
// console.log(name);
let {str, age} = obj;
console.log(str);
console.log(age);
*/
/*
import {name as str} from "./a.js";
console.log(name);
console.log(str);
*/
/*
ES6模块化的第二种方式
导出数据: export default xxx;
导入数据: import xxx from "path";
* */
/*
注意点:
1.如果是通过export default xxx;导出数据, 那么在接收导出数据的时候变量名称可以和导出的明白不一致
2.如果是通过export default xxx;导出数据, 那么在模块中只能使用一次export default
* */
/*
// import name from "./b.js";
import str from "./b.js";
console.log(str);
*/
/*
import name from "./b.js";
import age from "./b.js";
console.log(name);
console.log(age);
*/
/*
import {name, age} from "./a.js";
console.log(name);
console.log(age);
*/
/*
// 两种方式混合使用
import Person,{name, age, say} from "./c.js";
let p = new Person();
console.log(p);
console.log(name);
console.log(age);
say();
*/
// const icon = require("./xhh.jpg");
// const _ = require("./index.css");
import icon from "./xhh.jpg";
import "./index.css";
let oImg = document.createElement("img");
oImg.src = icon;
oImg.setAttribute("class", "size");
document.body.appendChild(oImg);
webpack-less-loader
less-loader
自动将 less 转换为 CSS。
less-loader 使用
① 安装 less
npm install --save-dev less
② 安装 less-loader
npm install --save-dev less-loader
③ 配置 less-loader
{
test: /\.less$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "less-loader"
}]
}
📖 注意点
- 因为 loader 是从 右 至 左 从 下 至 上,所以必须先由 less-loader 处理往后才能交给其他 loader 处理
webpack-sass-loader
scss-loader
🧀 自动将 scss 转换为 css
scss-loader 使用
① 安装 scss
npm install --save-dev node-sass
② 安装 scss-loader
npm install --save-dev sass-loader
③ 配置 scss-loader
{
test: /\.scss$/,
use: [{
loader: "style-loader" // 将 JS 字符串生成为 style 节点
}, {
loader: "css-loader" // 将 CSS 转化成 CommonJS 模块
}, {
loader: "sass-loader" // 将 Sass 编译成 CSS
}]
}
📖 注意点
- 因为 loader 是从右 至左 从下 至上,所以必须先由 sass-loader 处理往后才能交给其他 loader 处理
webpack-postcss-loader
什么是 PostCSS ?
- 官方文档
- PostCSS 和 sass/less 不同, 它不是 CSS 预处理器
- PostCSS 是一款使用插件去转换 CSS 的工具
- PostCSS 有许多非常好用的插件
- 例如
autoprefixer
(自动 补全 浏览器 前缀)postcss-pxtorem
(自动把 px 代为转换成 rem )- ... ...
使用 PostCSS 自动补全浏览器前缀
① 安装 postcss-loader
npm i -D postcss-loader
② 安装需要的插件
npm i -D autoprefixer
③ 配置 postcss-loader
- 在 css-loader or less-loader or sass-loader 之前添加
postcss-loader
④ 创建 postcss-loader 配置文件
- postcss.config.js
- 文档
⑤ 在配置文件中配置 autoprefixer
module.exports = {
plugins: {
"autoprefixer": {
"overrideBrowserslist": [
// "ie >= 8", // 兼容IE7以上浏览器
// "Firefox >= 3.5", // 兼容火狐版本号大于3.5浏览器
// "chrome >= 35", // 兼容谷歌版本号大于35浏览器,
// "opera >= 11.5" // 兼容欧朋版本号大于11.5浏览器,
"chrome >= 36", // 如果需要适配的浏览器完全兼容则不会添加前缀
]
}
}
};
使用 PostCSS 自动将 px 转换成 rem
-
安装 postcss-pxtorem
npm install postcss-pxtorem -D
在配置文件中配置 postcss-pxtorem
"postcss-pxtorem": {
rootValue: 100, // 根元素字体大小
// propList: ['*'] // 可以从px更改到rem的属性
propList: ["height"]
}
属性名 | 作用 |
---|---|
rootValue (Number) | root 元素的字体大小。 |
unitPrecision (Number) | 允许 REM 单位增长到的十进制数。 |
propList ( array ) | 可以从 px 更改到 rem 的属性。 |
值需要精确匹配。
使用通配符 * 启用所有属性。 示例:['*']
在单词的开头或者结尾使用 *。 ( ['*position*'] 将匹配 background-position-y )
使用 与属性不匹配。! 示例:['*','letter-spacing']!
将"非"前缀与其他前缀合并。 示例:['*','font*']!
属性名 | 作用 |
---|---|
selectorBlackList ( array ) | 要忽略和离开的选择器。 |
如果值为字符串,它将检查选择器是否包含字符串。
['body'] 将匹配 .body-class
如果值为 regexp,它将检查选择器是否匹配正则表达式。
[/^body$/] 将匹配 body,但不匹配 .body
属性名 | 作用 |
---|---|
replace (Boolean) | 替代包含 rems 的规则,而不是添加回退。 |
mediaQuery (Boolean) | 允许在媒体查询中转换 px。 |
minPixelValue (Number) | 设置要替换的最小像素值。 |
突然感觉淡淡不忧伤了, 过去麻烦的事 webpack 都帮我们做完了
webpack-css-loader模块化
默认情况下 通过 import "./xxx.css" 导入的样式 是 全局样式
也就是 只要 被导入, 在其它 文件中 也可以 使用
如果想要导入的 CSS 文件只在 导入 的 文件中 有效, 那么就需要开启 CSS 模块化
{
loader: "css-loader",
options: {
modules: true // 开启CSS模块化
}
}
然后在 导入 的 地方 通过 import xxx from "./xxx.css" 导入
然后在使用的地方通过 xxx.className 方式使用即可
webpack-iconfont-loader
如何打包字体图标
字体图标中也用到了 url 用到了文件, 所以我们需要通过 file-loader 来处理字体图标文件
{
test: /\.(eot|svg|ttf|woff|woff2)$/,
use:[{
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "font/",
}
}]
}
webpack-html-plugin
什么是插件 (plugin) ?
plugin 用于扩展 webpack 的功能。
当然 loader 也是变相的扩展了 webpack ,但是它只专注于转化文件这一个领域。
而 plugin 的功能更加的丰富,而不仅局限于资源的加载。
什么是 HtmlWebpackPlugin ?
HtmlWebpackPlugin 会在打包结束之后自动创建一个 index.html , 并将打包好的 JS 自动引入到这个文件中。
HtmlWebpackPlugin 使用
- 安装 HtmlWebpackPlugin
npm install --save-dev html-webpack-plugin
- 配置 HtmlWebpackPlugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
plugins: [new HtmlWebpackPlugin()]
webpack-clean-plugin
什么是 clean-webpack-plugin ?
webpack-clean-plugin 会在打包之前 将我们指定的文件夹清空
应用场景 每次打包前 将dist 目录清空, 然后再存放 新打包的内容, 避免 新老混淆问题
clean-webpack-plugin 使用
- 官方文档
- 安装 clean-webpack-plugin
npm install --save-dev clean-webpack-plugin
- 配置 clean-webpack-plugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
plugins: [new CleanWebpackPlugin()]