webpack的基础配置已经学习过无数遍,每次都是学完就忘,这次决定记录下来,把自己学习的过程记录下来,一是为了加强记忆,二是为了以后方便回顾。
webpack是一款目前来说应用特别广泛的打包工具,也是提升前端开发level的一个重要技能。本篇主要探讨下webpack的入口、输出等,比较基础如果已经非常熟悉webpack了 可不必细读也可绕道。
官网的定义:(官网地址)
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle。
webpack是一个静态模块打包器,所谓的静态模块,包括脚本、样式表和图片等等。它所做的事情是:分析项目结构,根据资源引用构建出一个依赖关系图,然后再将模块划分打包出一个或多个bundle。
先理解webpack的四个核心概念
先在全局安装webpack
npm install webpack webpack-cli –g
从 webpack v4.0.0
开始,可以不用引入一个配置文件,直接通过命令行创建,这里的entry和output就对应了上述概念中的入口和输入。
webpack <entry> [<entry>] -o <output>
举个栗子
原文件
// demo1/index.js
console.log('hello webpack')
打包
webpack index.js -o dist/bundle.js
最后生成的目录
我们也可以在项目目录新建一个html引入打包后的bundle.js文件查看效果。
上面演示了命令行打包的方式,然而实际项目都比较复杂需要很多配置,所以我们尝试下用配置文件来打包。
配置文件的命令如下
webpack [--config webpack.config.js]
项目结构
webpack-demo/demo2
|- package.json
|- webpack.config.js
|- /dist
|- index.html
|- /src
|- index.js
webpack.config.js
const path = require('path');
// 通过module.exports导出一个配置对象,还可以导出为一个函数或者是Promise 有兴趣可以自己去了解
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};
运行
webpack --config webpack.config.js
每次都使用webpack [--config webpack.config.js]
来指定配置文件也是有些繁琐的,我们可以用npm脚本来解决这个问题
先用npm init
生成一个package.json
文件,然后再修改scripts项里的内容
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
// 添加build
"build": "webpack"
},
这里的webpack没有指定配置文件是因为webpack打包的时候默认会运行当前目录下的webpack.config.js
文件
npm run build
在 webpack 配置中有多种方式定义 entry 属性
用法:entry: string|Array
如同我们在webpack.config.js
中写到的一样
module.exports = {
entry: './src/index.js',
...
}
上面单个入口文件的entry写法是下面的简写
module.exports = {
entry: {
main: './src/index.js'
},
...
}
当我们的页面需要多个模块,因此就需要把它们的依赖导向(graph)到一个“chunk”时,传入数组的方式就很有用。这里就是把index.js
、list.js
、detail.js
这三个模块打包到同一个bundle.js
中并在页面index.html
中引用
// demo2/webpack.config.js
module.exports = {
entry: [
'./src/index.js',
'./src/list.js',
'./src/detail.js'
],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
}
// demo2/src/list.js
function setElement() {
var element = document.createElement('div');
element.innerHTML = 'hello webpack demo2 list'
return element;
}
document.getElementById('list').appendChild(setElement());
// demo2/src/detail.js
function setElement() {
var element = document.createElement('div');
element.innerHTML = 'hello webpack demo2 detail'
return element;
}
document.getElementById('detail').appendChild(setElement());
//demo2/index.html
<body>
<div id="list">div>
<div id="detail">div>
body>
<script src="./dist/bundle.js">script>
// ...
有时候我们的项目可能会有不止一个页面,需要将多个页面分开打包,entry支持传入对象的方式。
module.exports = {
// 对象形式的入口文件
entry: {
home: './src/index.js',
list: './src/list.js',
detail: './src/detail.js'
},
...
}
这时候就会分别打包三个入口js文件并且生成三个bundle文件,三个文件的名字在output中定义,所以打包结果在output中测试。
在 webpack 中配置 output 属性的最低要求是,将它的值设置为一个对象,包括以下两点:
虽然entry可以有多个入口文件,但是只能配置一个output
module.exports = {
// 单个入口
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
}
};
这里根据entry单入口的情况配置的output,如果entry是多入口的情况还这样配置就会报错,Conflict: Multiple chunks emit assets to the same filename
即多个文件资源有相同的文件名称,webpack提供了占位符来确保每一个输出的文件都有唯一个名称
module.exports = {
// 对象形式的入口文件
entry: {
home: './src/index.js',
list: './src/list.js',
detail: './src/detail.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
// filename: 'bundle.js'
// 多文件入口时的output
filename: '[name].bundle.js',
}
};
这样打包出来的文件就会根据entry中键值名称来生成多个不同的文件名。
占位符
占位符 | 描述 |
---|---|
[hash] | 模块标识符的hash |
[chunkhash] | chunk内容的hash |
[name] | 模块名称 |
[id] | 模块标识符 |
[query] | 模块的query,例如:文件名?后面的字符串 |
Module、Chunk和Bundle的概念
自动生成页面
在上面的代码中我们都是手动创建html文件并引入打包后的js文件,这样不够自动化如果生成bundle引入了hash值,那么每次打包之后的js文件名也要重新替换,所以我们需要一个自动生成并引入打包后js的插件。
npm install --save-dev html-webpack-plugin
在entry入口文件为对象时我们引入了三个入口文件并在output中打包了三个bundle文件,在三个页面分别引入这三个文件
// demo3/webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
// 对象形式的入口文件
entry: {
home: './src/index.js',
list: './src/list.js',
detail: './src/detail.js'
},
output: {
path: path.resolve(__dirname, 'dist'),
// filename: 'bundle.js'
// 多文件入口时的output
filename: '[name].bundle.js',
},
plugins: [
new HtmlWebpackPlugin({
template: './index.html',
filename: 'home.html',
chunks: ['home']
}),
new HtmlWebpackPlugin({
template: './detail.html',
filename: 'detail.html',
chunks: ['detail']
}),
new HtmlWebpackPlugin({
template: './list.html',
filename: 'list.html',
chunks: ['list']
})
]
};
以index.html为模版再创建list.html和detail.html 不用引入bundle文件,会根据配置文件在打包后自动引入。
打包后的文件目录
// demo3/dist/home.html
<body>
<script src="home.bundle.js">script>
body>
// demo3/dist/list.html
<body>
<div id="list">div>
<script src="list.bundle.js">script>
body>
// demo3/dist/detail.html
<body>
<div id="detail">div>
<script src="detail.bundle.js">script>
body>