webpack4入门和多文件打包尝试

简介

按照webpack官网的说法,webpack本质上是javascript应用程序的静态资源打包器(static module bundler),它可以将模块按照依赖和规则打包成符合生产环境部署的前端资源。webpack可以将按模块异步加载按需引用,通过loader的转换还可以将任何资源看作模块,比如css、图片、json、commonjs模块、amd模块、es6模块等。如今webpack的大版本更新到4.x了,让我们看下如何使用。

1.安装使用

新建一个文件夹,依次执行:

npm init
npm i webpack webpack-cli webpack-server -D

即可开始使用webpack。在文件夹中新建文件夹 srcdist 和文件webpack.config.js,其中 src 为打包的源目录用来存放我们要打包的文件,dist 为输出目录,webpack.config.js 是我们配置webpack打包相关参数的文件。

  • 项目目录
  • webpack.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
//webpack.config.js
const path = require('path')

module.exports = {
// 打包模式,可选development和production
mode: 'development',
// 配置入口文件
entry: './src/index.js',
// 配置输出文件
output: {
// 输出路径
path: path.resolve(__dirname, './dist'),
// 输出文件名称
filename: 'build.js'
},
// 模块,可以使用各种loader,比如css转换,图片压缩等
module: {},
// 插件,用于生成模板和其它功能
plugins: [],
// 可配置本地的webpack开发服务功能
devServer: {}
}

编写好webpack.config.js之后就使用命令npx webpack开始执行打包了。webpack的打包机制,只能以js文件为入口,如果你需要打包图片,css,字体,svg等资源,必须使用es6或commonjs等模块加载规范在入口文件中引入,否则是没法进行打包构建的。

  • module和一些loader的使用

module可以使用loader处理引入的模块,支持的模块类型有CoffeeScript,TypeScript,ES5/6,sass,less,stylus。模块的依赖方式有:

1.ES2015 import 语句
2. CommonJS require() 语句
3. AMD definerequire 语句
4. css/sass/less 文件中的 @import 语句
5. 样式(url(...))或 HTML 文件(<img src=...>)中的图片链接(image url)

下面我用一些loader来介绍module的用法,注意使用loader之前需要使用npm安装对应的loader(npm i xxx-loader -D)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// webpack.config.js
module.exports = {
mode: '',
entry: '',
output: {},
module: {
rules: [
{
test: /\.css$/, // 匹配css文件模块
use: ['style-loader', 'css-loader'] // 使用对应的loader处理
},
{
test: /\.(png|gif|jpe?g|svg)$/, // 匹配图片文件
use: [{
loader: 'file-loader',
options: {
name: '[path][name].[ext]?[hash]',
// 会输出类似下面这样的结果
// path/to/file.png?e43b20c069c4a01867c31e98cbce33c9
}
}]
},
{
test: /\.(html)$/, // 用来匹配html文件模块(html需要通过插件引入?),可以将html标签中引入的图片资源进行打包
use: [{
loader: 'html-loader',
options: {
attrs: ['<tag>:<attribute>'] // <tag>为引入图片的标签名,<attribute>为引入图片的属性名
}
}]
}
]
},
plugins: [],
devServer: {}
}

通过上面例子中几个loader的使用,大致的介绍了模块的作用和用法。如果没有你需要的功能,可以去webpack官网上去寻找。

另外还有一个图片打包url-loader,需要注意它和file-loader的区别。url-loader可以说是file-loader的进一步封装,可以将图片转换为base64格式内联在代码中,这样可以减少图片加载的http请求。

  • plugins插件的使用

plugins也是webpack的重要功能之一,借助插件我们可以实现loader无法完成的工作。要使用插件之前,同样需要使用npm安装(npm i xxx -D),并且在webpack.config.js中要引用该插件。下面我简单介绍几个插件的用法,想要更完整的资料可以访问webpack插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// webpack.config.js
const path = require('path')
// 使用插件之前需要先加载对应的plugin
const CleanWebpackPlugin = require('clear-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')

module.exports = {
mode: '',
entry: {
a: './src/a.js', // 可以引入多个入口文件
b: './src/b.js'
},
output: {
path: path.resolve(__dirname + '/dist/'),
filename: '[name].[hash:8].js' // 输出多个结果,文件名带hash值
},
module: {},
plugins: [
// 每次构建完成后先清理一遍dist目录
new CleanWebpackPlugin(['dist']),
// 生成html文件到输入目录
new HtmlWebpackPlugin({
// 可以以src目录下的html源文件为模板
template: './src/index.html',
// 在目标目录下生成目标文件
filename: './dist/index.html',
chunks: ['a', 'b'] // 这个参数配合entry可以将打包的模块以<script></script>的形式加载到html文件中
}),
// 该插件可以将源目录中的文件直接复制到目标目录中
new CopyWebpackplugin([{
from: './src/*.css', // 选择源目录下的所有css文件
flatten: true // 选择拷贝文件还是包括文件夹,默认是false
}])
],
devServer: {}
}
  • devServer

devServer可以在本地搭建一个webpack构建服务环境

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// webpack.config.js
module.exports = {
mode: '',
entry: {},
output: {},
module: {},
plugins: [],
devServer: {
contentBase: '/dist', // 服务的内容目录
port: 4396, // 搭建在本地的服务的端口号
compress: true, // 服务开启gzip压缩
open: true // 自动打开本地浏览器
}
}

同时将项目目录下的package.json改写一下。

1
2
3
4
5
6
// package.json
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start": "webpack-dev-server", // 开启本地的webpack开发服务环境
"build": "webpack" // 执行打包
}

之后我们就可以执行npm run startnpm run webpack开启服务,执行打包。

2.多文件入口打包

多文件打包的本质就是在入口entry添加多个打包入口,在上面介绍plugins的HtmlWebpackPlugins时就用到了两个入口。我们自然而然的想到有多少个入口文件,就在entry里面添加几个入口不就好了。这样虽然可以实现多文件打包,但是每次我们新加一个入口都要手动添加,非常麻烦。所以我们想办法匹配获取到源目录下的所有的入口文件,然后添加到entry中即可。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function getEntry () {
let globPath = 'src/**/*.html' // 匹配src目录下的所有文件夹中的html文件
// (\/|\\\\) 这种写法是为了兼容 windows和 mac系统目录路径的不同写法
let pathDir = 'src(\/|\\\\)(.*?)(\/|\\\\)' // 路径为src目录下的所有文件夹
let files = glob.sync(globPath)
let dirname, entries = []
for (let i = 0; i < files.length; i++) {
dirname = path.dirname(files[i])
entries.push(dirname.replace(new RegExp('^' + pathDir), '$2').replace('src/', ''))
}
return entries
}

function addEntry () {
let entryObj = {}
getEntry().forEach(item => {
entryObj[item] = resolve(__dirname, 'src', item, 'index.js')
})
return entryObj
}

通过上面两个方法我们就能获取到src目录下的所有入口文件。下面我们看webpack.config.js如何修改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// ...
{
// entry: resolve(__dirname, "src/home/index.js")
// 改为
entry: addEntry()
//...
}
// ...

getEntry().forEach(pathname => {
let conf = {
filename: pathname.replace('src/', '') + '.html',
template: path.join(__dirname, 'src', pathname, 'index.html'),
chunks: Array.call([], pathname)
}
webpackconfig.plugins.push(new HtmlWebpackPlugin(conf))
})

这样我们就能够实现自动的匹配所有入口文件和要生成的html模板文件,同时在HtmlWebpackPlugin插件使用时,也自动添加了多个模板入口,在目标目录下生成多个html文件。

上面只是大致介绍了多入口的思路,具体代码可以看我实现的一个demo多页面打包

参考文章

webpack文档

webpack4.x入门配置

webpack多入口文件页面打包配置

webpack前端多页项目工程


作者简介: 宫晨光,人和未来大数据前端工程师。