这篇文章主要就是一步一步地,实现用webpack配置一个简单的web开发环境。
初始化文件夹,新建配置文件和测试代码
新建一个空的文件夹,这里就叫做webpack-basic-project,然后在文件夹下面执行
npm init -y
安装webpack依赖
yarn add --dev webpack webpack-cli webpack-dev-server
新建一个webpack的配置文件webpack.config.js
新建一个babel配置文件.babelrc
新建src文件夹,并添加index.js,index.html,index.scss,加入测试代码
index.js:
import "./index.scss";
function test() {
var root = document.getElementsByClassName("root")[0];
var p = document.createElement("p");
var text = document.createTextNode("hello world");
p.appendChild(text);
root.appendChild(p);
}
test();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>webpack basic sample</title>
</head>
<body>
<div class="root"></div>
</body>
</html>
index.scss
.root {
color: red;
}
也就是这个时候我们的文件夹结构是:
配置单页应用
一个最基本的配置是这样的
module.exports = {
entry: {},
mode: "",
output: {},
module: {
rules: [
]
},
plugins: []
}
mode
由于webpack4在production模式下会启动js压缩,为了方便看效果,我们先用开发模式吧
mode: "development"
entry
我们先添加entry,也就是入口文件
entry: {
index: "./src/index.js"
},
output
然后添加output,也就是编译后输出的文件夹,我们最后通过浏览器访问的也就是这里的。
output: {
path: path.join(__dirname, "dist"),
// publicPath: "./" 会给引入的文件前面加个前缀,主要是用于生产环境
filename: "[name].js"
},
loader
接着配置Loader,loader就是用来解析文件的。我们需要解析的就是js,css,图片、字体文件。一个一个说明。
解析js: 用babel-loader
安装依赖:
- @babel/core是babel的核心api包,必须要安装。
- @babel/preset-env 它提供一个target参数,可以让我们设置要支持的目标环境,从而能用不同的解析方式去转换js。官方推荐通过新建一个.browserslistrc来设置。
- @babel/preset-react 考虑到后面要用react加进去的。不需要的可以不添加。
yarn add --dev @babel/core @babel/preset-env babel-loader @babel/preset-react
在webpack.config.js里添加babel-loader
module: {
rules: [
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
use: "babel-loader"
}
]
}
编辑.babelrc
{
"presets": ["@babel/preset-env", "@babel/preset-react"],
"plugins": []
}
解析scss
安装依赖
- sass-loader:转换sass为css
- css-loader: 解析css
- mini-css-extract-plugin: 把css提取成一个独立的文件
yarn add --dev sass-loader node-sass css-loader mini-css-extract-plugin
由于loader是链式调用,从右到左,也就是最右边的loader执行完的结果会传递给它旁边的Loader。所以我们写的顺序是sass-loader->css-loader->mini-css-extract-plugin
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
module: {
rules: [
{
test: /.scss$/,
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
}
]
}
}
解析图片跟字体
安装依赖
yarn add --dev file-loader
添加配置
module: {
rules: [
{
test: /.(png|jpg|gif|jpeg)$/,
use: [
{
loader: "file-loader"
}
]
},
{
test: /.(woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: "file-loader"
}
]
}
]
}
plugins
安装依赖
yarn add --dev html-webpack-plugin clean-webpack-plugin
- html-webpack-plugin:用于根据html模板,生成一个新的html文件,把我们打包出来的js文件嵌入到html中
- clean-webpack-plugin:用于每次打包前都把dist文件夹清空。
- mini-css-extract-plugin:在loader那里已经安装过了,用于把打包出来的css文件提取到一个独立的文件,而不是嵌入在style标签里。
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, `./src/index.html`),
filename: "index.html",
chunks: ["index"],
inject: true
}),
new MiniCssExtractPlugin({
filename: "[name].css"
}),
new CleanWebpackPlugin()
],
devServer
由于我们开发模式下使用webpack-dev-server,所以这里设置一下热替换
module.exports = {
devServer: {
hot: true
}
}
最后,在package.json下面添加启动命令
"scripts": {
"build": "webpack --config webpack.config.js",
"dev": "webpack-dev-server --config webpack.config.js --open"
},
这个时候,我们执行npm run build,就会发现在dist文件夹下面已经有输出了。打开index.html,可以看到它引入了index.js跟index.css,打开也确实是输出了hello world。
执行npm run dev,打开http://localhost:8080,也可以看到index.html的内容。由于webpack-dev-server的输出是在内存中的,所以我们这个时候是不会创建dist文件夹的。
改成多页应用
准备测试代码
那就在src下新建一个文件夹,就叫search/search.js.由于我们准备让search.js跟index.js功能差不多,干脆直接新建一个common.js来写这个函数,然后search.js跟index.js去调用它。
common/common.js
function test(type) {
var root = document.getElementsByClassName("root")[0];
var p = document.createElement("p");
var text = document.createTextNode(`${type} world`);
p.appendChild(text);
root.appendChild(p);
}
export default test;
search/search.js
import test from "../common/common.js";
test("search");
index.js
import "./index.scss";
import test from "./common/common.js";
test("hello");
这时的文件夹结构是:
修改webpack配置
这里主要修改两个地方,添加一个入口entry来打包search.js,同时也添加一个新的html页面去引用search.js.
entry: {
index: "./src/index.js",
search: "./src/search/search.js"
},
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, `./src/index.html`),//引入html模板
filename: "index.html", // 打包出来的html模板名称
chunks: ["index"], // 这里的chunks就是对应上面entry打包出来的js文件
inject: true
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, `./src/index.html`),
filename: "search.html",
chunks: ["search"],
inject: true
}),
]
这时候我们再执行npm run build就可以发现dist下面已经打包出两套页面文件,可以直接打开index.html跟search.html看打包后的结果。执行npm run dev,访问http://localhost:8080/search.html跟http://localhost:8080/index.html也可以看到我们这两个文件的执行结果。
提取公共部分
common.js其实在两个文件都被用到了,这个时候,我们会希望把它打包成一个独立的文件。
添加配置:
module.exports = {
optimization: {
splitChunks: {
minSize: 0,
cacheGroups: {
common: {
name: "commons",
chunks: "all",
minChunks: 2, // 引用大于两次就独立打包出来
priority: 10
}
}
}
},
}
这个时候在html的chunks也要引入common.js,才能让页面正常工作。
plugins: [
new HtmlWebpackPlugin({
template: path.join(__dirname, `./src/index.html`),
filename: "index.html",
chunks: ["index", "commons"], // 加入common.js
inject: true
}),
new HtmlWebpackPlugin({
template: path.join(__dirname, `./src/index.html`),
filename: "search.html",
chunks: ["search", "commons"],
inject: true
})
}
执行npm run build,可以看到common.js已经被独立打包出来了。并且在html里面也有引入common.js。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。