webpack是干嘛的?
- 转译代码(ES6转为ES5,SCSS转为CSS)
- 构建build
- 代码压缩
- 代码分析
打印出一个包的版本信息
npm info webpack
1. 用webpack转译JS
安装webpack可以本地安装,按照官网上的步骤:
在src目录里新建一个index.js文件,在终端:
npm init -y //生成package.json
yarn add webpack webpack-cli --dev //本地安装
出现node_modules目录,里边的.bin/webpack是可执行的文件
运行webpack:
npx webpack
npx可以自动找到webpack的路径,执行这句命令后,会出现一个dist目录,里边有一个main.js文件。
由于我们没有全局安装,只是把webpack本地安装在node_modules里。可以手动找:
./node_modules/.bin/webpack
webpack会智能的把JS代码转译成IE或低级浏览器能看懂的代码。变成能在所有浏览器运行的代码。
webpack.config.js
但是运行后发现有警告

按照官网的教程:

var path = require("path");
module.exports = {
mode: "development",
};
再npx webpack ,就没有警告了。
那'development'或'production'模式有什么区别呢?
'development'是给开发者看的,开发过程中可以设。代码里有很多注释。'production'是给用户看的,要开发完了可以设成这个模式。两个模式怎么切换后边会讲。
配置entry 和 output
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "main.js",
},
};
运行npx webpack。entry是入口文件,output是出口文件。如果不写,默认把src里的index.js转译成dist目录里的main.js。也可以改成其他文件名。
找找其他的配置:搜索 webpack filename hash,点击 caching(缓存),看到把filename改成了:

2. 理解文件名中hash的用途
HTTP缓存
第一次访问baidu.com,会首先加载index.html,再去服务器下载,引入其他css,js文件。关闭页面再次访问时,如果全部都要重新下载,性能太低。所以在http的响应头里加缓存控制:cache-control: public, max-age=31536000 表示任何人都可以缓存,保留时间是一年,一年之内再次来访问,从内存或硬盘里取就可以,不需要再去服务器下载。
如果其中的css文件要更新怎么办?缓存是根据文件名变化的,而webpack会自动一一对应。也就是说,如果我更改了文件的内容,再次运行,webpack会自动生成另一个文件,文件名和内容是哈希对应的。当再次加载页面时,index.html看到引入的文件名变了,就会马上去服务器下载新的文件,放在内存里。
index.html是不会缓存的,每次都是要重新下载的。
module.exports = {
mode: "development",
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].[contenthash].js",
},
};
所以webpack这个功能,就是根据内容产生一个哈希,只要内容变了,就会产生一个新的文件。
3. yarn build
因为每次webpack后都会生成一个新的文件,所以在npx webpack之前要先删掉dist rm -rf dist 把这两句话用一个build代替:
//package.json
"scripts": {
"build": "rm -rf dist && webpack",
"test": "echo \"Error: no test specified\" && exit 1"
},
之后要运行,就只yarn build就可以
4. webpack生成HTML
安装
yarn add html-webpack-plugin --dev
配置
//webpack.config.js
var HtmlWebpackPlugin = require("html-webpack-plugin"); //新加的
var path = require("path");
module.exports = {
//...//
plugins: [new HtmlWebpackPlugin()], //新加的
};
此时yarn build ,会在dist里默认生成一个index.html文件,是空的,自动引入js。 而且,如果我修改了js内容,html里引入的js文件名也会自动更新。

new HtmlWebpackPlugin({
title: "demo",
template: "src/assets/index.html",
}),
如果只配置了title,在dist/index.html里title标签就变了。
template是模板,表示以"src/assets/index.html"这个文件为模板生成html。同时也要在src里创建目录,文件。当assets/index.html是个空文件时,可以看到dist/index.html里只有一句script,说明确实是以它为模板生成的。
把assets/index.html写入内容,作为模板:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
<div id="app"></div>
</body>
</html>
title标签里的<>表示:生成的dist/index.html的title以配置文件里指定的title选项为准。
yarn build后,dist/index.html内容:

5. webpack引入css
先新建src/x.css,在x.js里引入css。
安装
yarn add css-loader --dev
yarn add style-loader --dev
配置
//webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
};
运行
yarn build
怎么预览页面看样式是否生效?
cd dist //预览dist里的html,所以先进入到dist目录
hs . -c-1
可以看到样式生效。原理?
在配置文件里,意思是:找到以.css结尾的文件,'css-loader'负责把css内容引入到js文件中,此时还未生效。需要'style-loader'把js里的css内容加一个style标签,放到head里,样式就生效了。两个loader负责不同的部分。
6. webpack dev server
在引入css时,如果要改代码,需要不断进入dist目录预览页面和回到上一级目录build之间切换,太麻烦了。
webpack dev server可以简化这个过程,加快开发。不需要build
1. 配置
//webpack.config.js 添加:
module.exports = {
mode: 'development',
entry:"",
devtool: 'inline-source-map',
}
2. 安装
yarn add webpack-dev-server --dev
//webpack.config.js 里在devtool下边添加:
devServer: {
contentBase: "./dist",
},
3. 添加脚本
//package.json
"scripts": {
"start": "webpack-dev-server --open", //添加
"build": "rm -rf dist && webpack",
},
--open:自动打开浏览器,也可以去掉,去掉之后要手动搜索:localhost:8080
4. 运行
yarn start
在终端运行这句命令后,就会开始开发。打开浏览器。
这样就不需要再使用http server和yarn build。如果改变代码,保存之后,页面会自动更新,不需要别的命令了。
并不会生成dist目录,直接在内存里搞定,不依赖dist
7. css抽成文件
上边是使用JS生成style标签,另一种方法:用CssExtractPlugin这个插件
还是要在js里import css文件
安装
yarn add mini-css-extract-plugin --dev
配置
//webpack.config.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //添加
module.exports = {
plugins: [
new HtmlWebpackPlugin({
title: "demo",
template: "src/assets/index.html",
}),
new MiniCssExtractPlugin({ //添加
filename: "[name].[contenthash].css",
chunkFilename: "[id].[contenthash].css",
}),
],
module: {
rules: [ //添加
{
test: /\.css$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "../",
hmr: process.env.NODE_ENV === "development",
},
},
"css-loader",
],
//use: ["style-loader", "css-loader"],
},
],
},
};
要把上一种方法的use删掉,因为只使用一个loader。
插件里的filename也要加.[contenthash],为了让生成的css文件名也是哈希的,可以随着内容更新,用于缓存。
运行
yarn build
在dist里生成了一个css文件,并且html里也自动引入了这个css文件

预览
yarn start
8. 两种模式切换
- 开发:用第一种模式,即JS生成style。使用
yarn start - 生产:用第二种模式,即抽成css文件。使用
yarn build
因为生成style标签很快,节省开发时间。而生产是最终给用户看的,需要缓存和生成css文件。
使用两个webpack.config.js文件
原来的默认文件用作开发,再复制一份新的叫webpack.config.prod.js用作生产。
webpack.config.js
//还是使用原来的use
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
webpack.config.prod.js
mode: "production", //改为production
hmr 选项删掉
package.json
"scripts": {
"start": "webpack-dev-server --open",
"build": "rm -rf dist && webpack --config webpack.config.prod.js",
},
指定yarn start时开发,使用默认的配置文件。
yarn build时生产,通过--config指定配置文件路径
继承思想
可以发现,两个配置文件除了css插件部分之外完全一样,所以根据继承的思想,把他们的共有属性放到一起。
新建一个webpack.config.base.js文件,
var HtmlWebpackPlugin = require("html-webpack-plugin");
var path = require("path");
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "[name].[contenthash].js",
},
plugins: [
new HtmlWebpackPlugin({
title: "demo",
template: "src/assets/index.html",
}),
],
};
webpack.config.js
var HtmlWebpackPlugin = require("html-webpack-plugin");
var path = require("path");
// require 引入
const base = require("./webpack.config.base.js");
module.exports = {
...base, //把base的所有属性抄到这里
devtool: "inline-source-map",
devServer: {
contentBase: "./dist",
}, //开发需要的属性
mode: "development",
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
},
};
webpack.config.prod.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
var HtmlWebpackPlugin = require("html-webpack-plugin");
var path = require("path");
const base = require("./webpack.config.base.js"); //引入
module.exports = {
...base, //抄base
mode: "production",
plugins: [
...base.plugins, //抄base的plugins属性
new MiniCssExtractPlugin({
filename: "[name].[contenthash].css",
chunkFilename: "[id].[contenthash].css",
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: "../",
},
},
"css-loader",
],
},
],
},
};
总结
-
webpack转译JS:
不需要其他操作,只要运行webpack,就可以把src/index.js转译成dist/main.js。使用了webpack的一个内置加载器:babel-loader
-
生成css:两种方法
- 使用style-loader+css-loader,生成style标签
- 使用mini-css-extract-plugin,生成css文件(插件是n对1,如果有两个css,也会在dist目录里生成一个css文件)
-
生成html:
把0个或1个html通过html-webpack-plugin生成dist/index.html。
