webpack快速入门教程
1、webpack 简介
- 什么是webpack?
- webpack是一个模块打包器(bundler)。
- 在webpack看来, 前端的所有资源文件(js/json/css/img/less/…)都是模块。
- 它将根据模块之间的依赖关系进行分析,生成对应资源。
2、核心概念
- entry(入口):指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始。
- output(输出):属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件。
- loader(加载器):webpack 本身只能处理 js/json 文件,loader 可以让webpack处理其他类型文件。
- plugins(插件):插件可以执行范围更广的任务,即loader无法完成的,插件或许可以完成。
- mode(模式):有生产模式 production 和开发模式 development 。
- 理解 loader
- loader 本质是运行在 Node.js 中的就是js代码。
- loader 一般以 xxx-loader 的方式命名,xxx 代表了这个 loader 对应的功能,比如 less-loader。
3、webpack 安装
全局安装,作为指令使用:npm install webpack@4 webpack-cli@3 -g
本地安装,作为本地依赖使用:npm install webpack@4 webpack-cli@3 -D
4、编译打包应用
-
创建js文件
- src/js/app.js
- src/js/module1.js
- src/js/module2.js
- src/js/module3.js
-
创建主页面:
- src/index.html
-
运行指令
-
开发
webpack src/js/app.js -o build/js/app.js --mode=development
webpack 能够编译打包 js 和 json 文件,并且能将 es6 的模块化语法转换成浏览器能识别的语法
-
生产
webpack src/js/app.js -o build/js/app.js --mode=production
production 配置能够压缩代码
-
-
结论:
- webpack只能够打包 js 和 json 文件。
- 能将ES6 的模块化语法进行代码打包,但ES6的其他语法不做转换。
- 能压缩代码。
-
不足之处:
- 不能将 js 的 es6 基本语法转化为 es5 语法
- 打包命令复杂
5、使用 webpack 配置文件
-
目的:在项目根目录定义配置文件,通过自定义配置文件,还原以上功能
-
文件名称:webpack.config.js
-
文件内容:
//node内置核心模块,用来设置路径。 const { resolve } = require('path'); //只能使用 CommonJS 规范暴露 module.exports = { // 入口文件配置 entry: './src/js/app.js', // 输出配置 output: { // 输出文件名 filename: './js/built.js', //输出文件路径配置 path: resolve(__dirname, 'build') }, // development 与 production 开发环境(二选一) mode: 'development' };
-
运行指令: webpack
6、打包 less 资源
less 文件 webpack 不能解析,需要借助 loader 编译解析,使用步骤如下:
- 创建less文件
- src/css/demo.less
- 入口app.js文件
//引入less 文件
import '../css/demo.less';
- 安装 loader
npm install css-loader style-loader less-loader@7 less --save-dev
webpack 4 现在不能直接安装 less-loader 最新版本, 要安装 less-loader@7 版本
-
webpack.config.js 配置 loader
module.exports = { ..... module:{ rules:[ { test:/\.less$/, // 检查文件是否以.less结尾(检查是否是less文件) use:[ // 数组中loader执行是从下到上,从右到左顺序执行 'style-loader', // 将样式模块打包进app.js文件中 'css-loader', // 将css样式变为CJS的一个样式模块 'less-loader' // 将less样式解析成css样式 ] } ] }, }
-
运行指令
webpack
7、JS 语法检查
ESLint(https://eslint.org) 能对 JS 基本语法错误、隐患进行提前检查,使用步骤:
-
安装loader
npm install eslint-loader eslint --save-dev
eslint 是语法检查的包
eslint-loader 是 eslint 在 webpack 中的 loader 包
-
webpack.config.js 配置 loader
module.exports = { .... module: { rules: [ .... { test: /\.js$/, //只检测js文件 exclude: /node_modules/, //排除node_modules文件夹 enforce: "pre", //提前加载使用 use: { loader: "eslint-loader" //使用eslint-loader解析 } } ] } }
-
创建
.eslintrc
文件 (位置要放到项目的根目录下){ "parserOptions": { "ecmaVersion": 6, // 支持es6 "sourceType": "module" // 使用es6模块化 }, "env": { // 设置环境 "browser": true, // 支持浏览器环境: 能够使用window上的全局变量 "node": true // 支持服务器环境: 能够使用node上global的全局变量 }, "globals": { // 声明使用的全局变量, 这样即使没有定义也不会报错了 "$": "readonly" // $ 不允许重写变量 }, "rules": { // eslint检查的规则 0 忽略 1 警告 2 错误 "no-console": 0, // 不允许出现 console "eqeqeq": 0, // 必须使用 === "no-alert": 0 // 不能使用 alert }, "extends": "eslint:recommended" // 使用eslint推荐的默认规则 }
-
运行指令
webpack
8、JS 语法转换
借助 Babel 可以将浏览器不能识别的新语法(ES6, ES7)转换成原来识别的旧语法(ES5)
-
安装loader
npm install babel-loader @babel/core @babel/preset-env --save-dev
@babel/core 是 babel 的核心库
@babel/preset-env 是 babel 的预设的工具包,默认可以将所有最新的语法转为为 ES5
babel-loader 是 babel 在 webpack 中的 loader 包
-
配置 loader
module: { rules: [ .... .... .... { test: /\.js$/, exclude: /node_modules/, use: { loader: "babel-loader", options: { presets: ['@babel/preset-env'] } } } ] }
-
运行指令
webpack
9、JS 兼容性处理
Polyfill 用来为旧浏览器提供它没有支持的较新的JS语法
-
安装 polyfill
npm install @babel/polyfill
-
app.js(入口文件)引入
import '@babel/polyfill';
10、打包样式文件中的图片资源
图片文件 webpack 不能解析,需要借助 url-loader编译解析
-
两张资源图片:
- 小图, 小于8kb: src/images/vue.png
- 大图, 大于8kb: src/images/react.jpg
-
在 less 文件中通过背景图的方式引入图片
.react { width: 200px; height: 200px; background: url('../images/react.png') no-repeat; background-size: cover; } .vue { width: 200px; height: 200px; background: url('../images/vue.png') no-repeat; background-size: cover; }
-
安装 loader
npm install url-loader --save-dev
备注:url-loader是对象file-loader的上层封装,使用时需配合file-loader使用。
-
webpack.config.js 配置 loader
module.exports = { ... ... module: { rules: [ ... ... { test: /\.(png|jpg|gif)$/, use: { loader: 'url-loader', options: { limit: 8192, // 8kb以下的图片会 base64 处理 outputPath: 'images', // 文件本地输出路径 publicPath: '../build/images', // 图片的url路径 name: '[hash:8].[ext]', // 修改文件名称和后缀 } } }, ] } }
-
运行指令
webpack
11、打包 HTML 文件
HTML 文件不能直接被 webpack 解析,需要借助 HtmlwebpackPlugin
插件编译解析
-
在 src 目录下创建 index.html 文件,注意不要在 HTML 中引入任何 CSS 和 JS 文件
-
安装插件
npm install html-webpack-plugin@4 --save-dev
webpack4中要使用html-webpack-plugin@4
-
webpack.config.js 修改配置
// 插件都需要手动引入 const HtmlwebpackPlugin = require('html-webpack-plugin'); ... module.exports = { ... plugins: [ new HtmlwebpackPlugin({ template: './src/index.html', // 设置要编译的 HTML 源文件路径 }) ] }
-
运行指令
webpack
src 目录就是源文件目录,所有的代码和资源都保存在该目录,index.html 也是如此
12、打包 HTML 中图片资源
url-loader 只能处理 JS 和 CSS 中引入的图片,无法处理 HTML 中的 img 图片,需要 html-loader 处理。
-
src/index.html 添加 img 标签
<img src="./images/sun.jpg" alt="xxx">
-
安装loader
npm install html-loader@1 --save-dev
-
配置loader
module.exports = { ... module: { rules: [ ... { test: /\.(html)$/, use: { loader: 'html-loader' } } ] } }
-
运行指令
webpack
13、打包其他资源
字体文件需要借助 file-loader 编译解析,以 iconfont 为例,下载一个项目
- 将字体文件保存在
src/fonts
目录下
- src/fonts/iconfont.eot
- src/fonts/iconfont.svg
- src/fonts/iconfont.ttf
- src/fonts/iconfont.woff
- src/fonts/iconfont.woff2
-
创建 src/css/iconfont.less 并将 iconfont 的 css 样式粘到 less 文件中,并修改字体路径
@font-face { font-family: 'iconfont'; src: url('../fonts/iconfont.eot'); src: url('../fonts/iconfont.eot?#iefix') format('embedded-opentype'), url('../fonts/iconfont.woff2') format('woff2'), url('../fonts/iconfont.woff') format('woff'), url('../fonts/iconfont.ttf') format('truetype'), url('../fonts/iconfont.svg#iconfont') format('svg'); } .iconfont { font-family: "iconfont" !important; font-size: 16px; font-style: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; }
-
修改
src/index.html
<span class="iconfont"></span>
-
配置 loader
module.exports = { ... module: { rules: [ ... { test: /\.(eot|svg|woff|woff2|ttf|mp3|mp4|avi)$/, // 处理字体文件 loader: 'file-loader', options: { outputPath: 'fonts', name: '[hash:8].[ext]' } } ] } }
-
运行指令
webpack
14、自动编译打包运行
之前的操作,每次修改代码都需要重新执行 webpack 命令,可以使用 webpack-dev-server 自动打包运行
-
安装 loader
npm install webpack-dev-server -g npm install webpack-dev-server -D
-
修改 webpack.config.js
module.exports = { ... output: { path: resolve(__dirname, 'build'), filename: 'js/app.js', //1. 添加 devServer 服务后需要调整输出的路径 publicPath: '/' }, module: { rules: [ ... { test: /\.(png|jpg|gif)$/, use: { loader: 'url-loader', options: { limit: 8192, outputPath: 'images', name: '[hash:8].[ext]', //2. 删除 publicPath 配置 } } }, ] }, .... //3. 增加 devServer 配置 devServer: { open: true, // 自动打开浏览器 compress: true, // 启动gzip压缩 port: 3000, // 端口号 }, mode: 'development' }
-
现在就可以启动服务
webpack-dev-server
-
配置 package.json 中 scripts 指令,增加 server 配置
json
{
...
"scripts": {
"server": "webpack-dev-server"
},
...
}
-
运行指令
npm run server
15、热模替换功能
模块热替换 (HMR - Hot Module Replacement) 功能会在应用程序运行过程中替换、添加或删除模块,而无需重新加载整个页面。
修改 webpack.config.js 的 devServer 配置
module.exports = {
//index.html 不能自动刷新的解决方法
//新增一个入口,解决开启热模块替换后首页无法刷新的问题
entry: {
main:['./src/js/app.js','./src/index.html']
},
...
devServer: {
open: true,
compress: true,
port: 3000,
hot: true // 开启热模块替换功能
},
mode: 'development'
}
16、准备生产环境
webpack 可以使用不同的配置文件,进行不同的编译。
-
创建文件夹 config,将 webpack.config.js 复制两份
- ./config/webpack.dev.js
- ./config/webpack.prod.js
-
修改 webpack.prod.js 配置,删除 webpack-dev-server 配置
... module.exports = { entry: { main:['./src/js/app.js','./src/index.html'] }, //出口配置 output: { path: resolve(__dirname, '../build'), //1. 出口目录配置 filename: './js/bundle.js', publicPath: '/' }, ... //2. 设置 mode mode: 'production' //3. 删除 devServer 配置 }
-
修改 package.json 的指令
{
...
"scripts": {
"dev": "webpack-dev-server --config ./config/webpack.dev.js",
"build": "webpack --config ./config/webpack.prod.js"
}
...
}
- 开发环境指令
- npm run dev 用于开发环境 不打包文件
- npm run build 用于生产环境 打包文件 (打包后的index.html不能直接双击打开,需要启动服务)
17、清除打包文件目录
每次打包生成了文件,都需要手动删除,引入插件 clean-webpack-plugin
帮助我们自动删除上一次生成的文件
-
安装插件
npm install clean-webpack-plugin --save-dev
-
webpack.prod.js
引入插件//1. 引入插件 const { CleanWebpackPlugin } = require('clean-webpack-plugin'); ... module.exports = { ... plugins: [ new HtmlwebpackPlugin({ template: './src/index.html', }), //2. 配置插件 new CleanWebpackPlugin() ], }
-
运行指令
npm run build
18、提取 CSS 成单独文件
前面的 CSS 样式代码都是放在 style 标签中,这里可以借助 mini-css-extract-plugin 抽离 CSS 文件
-
安装插件
npm install mini-css-extract-plugin --save-dev
-
配置 webpack.prod.js
// 1. 引入插件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
...
module: {
rules: [
{
test: /.less$/,
use: [
MiniCssExtractPlugin.loader, // 2. 修改配置 loader
'css-loader',
'less-loader'
]
}
]
},
plugins: [
...
new MiniCssExtractPlugin({// 3. 配置插件
filename: "css/[hash:8].css",
})
]
...
}
-
运行指令
webpack
19、添加 CSS 兼容
- 安装 loader
npm install postcss-loader@4 autoprefixer --save-dev
- webpack.prod.js 配置 loader
module.exports = {
....
module: {
rules: [
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader', // 1. 设置 postcss-loader
'less-loader',
]
},
....
]
}
}
- 在项目根目录下添加 postcss.config.js 配置文件
module.exports = {
plugins: [
require('autoprefixer')
]
}
- 在项目目录下创建
.browserslistrc
这里一要加目标浏览器设置
chrome 50
last 1 versions
ie 10
iOS 7
- 运行指令:
npm run build
20、压缩 CSS
-
安装插件
npm install optimize-css-assets-webpack-plugin --save-dev
-
引入插件,配置插件
//1. 引入插件 const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin'); module.exports = { plugins: [ ... //2. 配置插件 new OptimizeCssAssetsPlugin() ], mode: 'production' }
-
运行指令
npm run build
附录
browserslist
browserslist 目标浏览器配置表,可以针对目标浏览器进行编译处理,避免不必要的兼容代码
配置的方法有两种,一种是在 package.json 中,一种是创建 .browserslistrc
package.json 形式
{
"browserslist": [
"> 1%",
"last 2 versions"
]
}
.browserslistrc
形式
> 1%
last 2 versions
配置规则介绍
规则 | 介绍 |
---|---|
> 1% | 全球超过1%人使用的浏览器 |
> 5% in US | 指定国家使用率覆盖 |
last 2 versions | 所有浏览器兼容到最后两个版本根据CanIUse.com追踪的版本 |
Firefox > 20 | 指定浏览器的版本范围 |
not ie <=8 | 排除 ie8 及以下 |
Firefox 12.1 | 指定浏览器的兼容到指定版本 |
since 2013 | 2013年之后发布的所有版本 |
not dead with > 0.2% | 仍然还在使用且使用率大于 0.2% |
last 2 Chrome versions | 最新的两个 Chrome 配置 |
cover 99.5% | 99.5% 的浏览器都是目标 |