说明: 网上很多教程,大各种各样的内容都有,自己研究的时候查了很多文档,出现了一些错误都一一记录下来.并且配置文件没有任何的封装,旨在能提炼出最关键的内容.
环境
webpack: 4
1. 要用到的插件:
html-webpack-plugin // 用于根据html模板生成页面
clean-webpack-plugin // 用于清除dist目录下的代码
extract-text-webpack-plugin // 用于提取出css到单个或者多个单独文件中
2. 项目目录
ProjectName
├ ─ dist // 准备发布代码时build出来的文件在这里(需在webpack.config.js中配置)
├ ─ node_modules
├ ─ src
├ ─ css
├ ─ index.css
├ ─ about.css
├ ─ js
├ ─ index.js
├ ─ about.js
├ ─ pages
├ ─ index.html
├ ─ about.html
├ ─ favicon.ico // 可有可无,因为我项目里放了,就写在这里了
├ ─ package.json
├ ─ webpack.config.js // webpack 配置文件
3. 开始
1. 创建项目
mkdir mutile-page-demo
cd mutil-page-demo
npm init -y
2. 创建目录
mkdir src
mkdir src/css
mkdir src/js
3. 创建文件(完全可以使用IDE创建出这个目录结构,不一定要使用命令行,我这里只是为了展示起来更直观
)
# 注意使用git-bash或Cmder命令行工具,windows命令行中是没有 touch命令的
touch webpack.config.js
touch ./src/pages/index.html
touch ./src/pages/about.html
touch ./src/css/about.css
touch ./src/css/about.css
touch ./src/js/about.js
touch ./src/js/about.js
4. 下面罗列文件内容,可以自己随便写,也可以copy下面的内容.
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>index</title>
<link rel="stylesheet" href="../css/index.css">
<script src="../js/index.js">
</script>
</head>
<body>
<div class="title">this is index.html</div>
<a href="about.html">about</a>
</body>
</html>
about.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>about</title>
<link rel="stylesheet" href="../css/about.css">
</head>
<body>
<div class="title">this is about.html</div>
<a href="index.html">index</a>
</body>
</html>
index.js
window.onload = function () {
var title = 'index'
var p = document.createElement('p')
p.innerText = 'append tag p from index.js!'
document.body.appendChild(p)
}
about.js
window.onload = function () {
var p = document.createElement('p')
p.innerText = 'append tag p from about.js!'
document.body.appendChild(p)
}
index.css
.title {
color: red;
}
about.css
.title {
color: blue;
}
5. 编写配置文件: webpack.config.js
module.exports 中有几个关键点:
- entry:
入口文件:
简单理解为,webpack从这里开始编译,接受的参数类型-
字符串,如:
entry: 'index.js'
# 配置单页应用 -
数组, 如:
entry: ['index.js', 'about.js']
-
对象(
我使用这种方式
): 如:
-
entry: {
index: path.resolve(__dirname, 'src/js/index.js'),
about: path.resolve(__dirname, 'src/js/about.js')
},
- output: 用于设置输出文件的配置(build)
- module: 相关loader配置
- plugins: 相关插件配置
- devServer: 开发环境启动的服务,hot reload 在这里配置
直接贴部分代码并说明
entry
entry: {
index: path.resolve(__dirname, 'src/js/index.js'), // 获得目标文件的绝对路径
about: path.resolve(__dirname, 'src/js/about.js')
},
output
path: path.resolve(__dirname, 'dist'), // 将build结果输出到 project 的 dist/ 目录下
filename: 'js/[name]-[hash].bundle.js' // 将js文件输出到 js/ 目录下
module.rules 配置
module: {
rules: [{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}]
},
image.png注意 style-loader要卸载css-loader的前面,否测会报错
plugins配置
new htmlWebpackPlugin({
filename: 'index.html', // 生成的html文件名称,可以同时指定输出的路径,如: /pages/index.html,将被输出到 /dist/pages/index.html
template: path.resolve(__dirname, 'src/pages/index.html'), // 模板位置
inject: 'head', // 控制webpack把js文件append到html的head还是body中,默认是body
title: 'index', // 传递title到生成的html中
chunks: ['index'], // 设置生成的html中要引入哪些js文件: chunk名称需要和entry中的属性保持一致,多个js以数组方式配置,如 chunks: ['index', 'about']
// favicon: path.resolve('favicon.ico'), // 设置hmtl的shortcut icon
// minify: { // 启用压缩功能
// removeComments: true, //删除注释
// collapseWhitespace: true //删除空格
// }
}),
new htmlWebpackPlugin({
filename: 'about.html',
template: path.resolve(__dirname, 'src/pages/index.html'),
inject: 'head',
title: 'about',
chunks: ['about']
}),
......如果有多个页面需要也这样写
devServer
{
// 注意设置了此属性将导致hot失效
// 并且会导致js中通过import引入css出现一些问题
// openPage: 'src/pages/index.html',
open: true, // 自动打开浏览器并访问页面
inline: true, // 内联模式实时刷新,推荐方式
hot: false, // 热更新,注意当设置为true时,会导致热更新失败,浏览器不再刷新代码,原因不知
port: 9527,
host: 'localhost',
// compress: true, // 启用压缩,会增加服务器端和客户端的负载
}
6 添加运行代码
在package.json的 scripts 中添加2行代码,保存!
"start": "webpack-dev-server --config webpack.config.js"
"build": "webpack --config webpack.config.js",
在命令行中执行: npm start
查看浏览器页面中,发现样式并没有生效
因为webpack中没有像entry那样的节点来单独配置css的输出,所以html中默认的link并不能让webpack帮我们把css文件一起打包
解决方法: 在index.js中import需要的css, webpack的思想是一切皆为模块,所以css也可以通过import引入.
修改index.js为:
import '../css/index.css' # 新增加的一行
window.onload = function () {
var p = document.createElement('p')
p.innerText = 'append tag p from index.js!'
document.body.appendChild(p)
}
保存后查看浏览器发现样式生效了
image.png
然后我们在命令行中执行一下: npm run build
查看procjet中生成了dist目录:
发现我们预想的css目录没有出现,但是如果查看 由index.js生成的文件末尾(需要格式化一下代码,也可以直接搜索名称为title的样式),会看到 index.css中的代码
image.png原来webpack把我们的css代码编译到了js中,在打开页面的时候,样式会被追加到html的style标签中.
为了解决这个问题,使用 extract-text-webpack-plugin 插件抽取css
7 使用 extract-text-webpack-plugin 插件抽取css
如果你还未安装此插件,需要安装
cnpm i -D extract-text-webpack-plugin
在webpack.config.js中,添加以下代码
const ExtractTextPlugin = require("extract-text-webpack-plugin");
将 modules.exports rules中 css的配置更改掉:
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
由
image.png
改为
image.png
在plugins节点中,添加一行
new ExtractTextPlugin({
filename: 'css/[name].css'
})
再次执行 npm run build
,得到正确的输出
8. 如果你仔细看,会发现当你修改过js文件后,再执行 npm run build
,会发现 /dist/js 中出现了多个带有不同hash串的 相同文件名. 比如: index-85eb01adecdeb439d2cb.bundle.js 和 index-fe758ed5a5b3da38a76e.bundle.js,见下图.
image.png
这是因为hash的原因,webpack在打包的时候会计算文件的hash值,如果文件被改动,那么整个编译出来的hash串也都会变化.(可以通过下面扩展中说明的chunkhash 和 contenthash来优化output节点中的 filename)
这时,最简单的方法就是build之前先清空掉dist,所以使用了 clean-webpack-plugin 插件
在 webpack.config.js 中加入一行
const {
CleanWebpackPlugin
} = require('clean-webpack-plugin'); // 文件夹清除工具
并且在plugins节点中增加:
new CleanWebpackPlugin(), // 清空dist文件夹
image.png
扩展:
hash和chunkhash、contenthash区别
hash: hash是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的hash值都会更改,并且全部文件都共用相同的hash值
chunkhash: chunkhash根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。
contenthash: 假设index.js引用了index.css,若使用chunkhash的话,只要js改变,那么css也会被重新构建。如何防止css被重新构建呢?
可以使用extract-text-webpack-plugin提取单独的css文件并使用contenthash,contenthash 只要文件内容不变,那么不会重复构建。
总结:
- 通过entry对象方式配置多入口
- 通过output将js输出到指定目录
- 通过html-webpack-plugin,指定输出多个index.html 页面
- 通过webpack-dev-server开启本地服务
- 通过import 'xxx.css' 配合 extract-text-webpack-plugin 插件修改,rules配置和在plugins中添加下面代码实现css抽离到单个文件或多个文件
new ExtractTextPlugin({ // 抽离到多个页面
filename: 'css/[name].css'
})
new ExtractTextPlugin("styles.css") // 抽离到单个页面
遇到的问题:
- 执行
npm run build
时报错
Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead
原因: extract-text-webpack-plugin还不能支持webpack4.0.0以上的版本。
解决方法: 安装最新版本
cnpm install --save-dev extract-text-webpack-plugin@next
发现的问题
- 如果plugins中配置了多个目录,并且有多个目录下同时拥有index.html,如果没有配置对应的index.html输出到指定的目录中,那么当
npm start
时自动打开的首页面是 new htmlWebpackPlugin()写在最后的一个页面,
比如:
new htmlWebpackPlugin({
template: path.resolve(__dirname, 'src/pages/zh-CN/index.html'),
inject: 'head',
title: 'index',
chunks: ['index'],
favicon: path.resolve('favicon.ico'),
filename: 'index.html',
}),
new htmlWebpackPlugin({
template: path.resolve(__dirname, 'src/pages/zh-TW/index.html'),
inject: 'head',
title: 'index',
chunks: ['index'],
favicon: path.resolve('favicon.ico'),
filename: 'index.html',
}),
new htmlWebpackPlugin({
template: path.resolve(__dirname, 'src/pages/test/index.html'),
inject: 'head',
title: 'index',
chunks: ['index'],
favicon: path.resolve('favicon.ico'),
filename: 'index.html',
}),
原因大概是,最后根据src/pages/test/index.html生成的index.html把前面的覆盖了.
- 当给devServer设置了
openPage: 'src/pages/zh-CN/index.html'
时,会导致hot失效,并且js中通过import引入css也会出现一些问题,并在浏览器中报错.
网友评论