直入正题,四个核心概念并结合实例
告诉webpack使用哪个文件作为构建依赖图的起点,比如指定app.js作为entry,webpack会分析app.js使用到的模块,并解析模块中使用到的模块以此类推,最终将前端静态资源按一定规则打包成一个或多个静态文件。
多个entry
一个项目可能有多个入口,首先多页面程序可能有多个entry,SPA应用也可能有多个入口(框架代码一个entry,业务代码一个entry)
entry的值
可以是 字符串 || 数组 || 对象 无论采用何种方式,entry都是入口的文件路径。
// webpack.conf.js
module.exports = {
// entry: './app.js' //字符串
//entry: ['./app.js', './index.js'] 数组形式
// 推荐对象格式 更加清晰和灵活
entry: {
index : './index.js',
app: './app.js'
}
}
一个模块化开发项目开发完成后到上线前,一般需要借助webpack打包生成dist目录,比如我们使用vue-cli
工具执行npm run build
后会在项目的主目录下生成dist目录(如果不了解vue-cli
没关系,暂时知道这个事实即可),那么这个dist目录以及打包后的文件名就是借助vue-cli已经内置好的webpack配置文件,指定了dist目录,和打包后生成的文件名。
简单来说,output就是告诉webpack通过入口entry按照模块依赖关系将打包好后的文件输出到哪里(指定文件夹或位置)以及文件名(打包后的文件bundles叫什么)。
最后线上环境会使用打包好的文件。
const config = {
entry: {
app: './xx/app.js' // 入口文件路径 并不一定是'./app.js'
},
output: {
path: '/home/xx', // 绝对路径
// filename: 'bundle.js'
filename: '[name].[hash:7].js' //采用hash动态生成文件名
}
}
上面说了entry,output两个webpack核心概念,下面让我们进行一些demo练习加深理解。
首先你需要安装node.js
和webpack
命令行工具采用git bash
你也可以使用你喜欢的命令行工具。
如何安装上述工具请参考官网或者其他教程。
step1
打开git bash
-> $mkdir webpack-demo
-> cd webpack-demo
step 2
这里我们验证webpack打包ES6 Modules
用你喜欢的编辑器打开webpack-demo文件夹,新建multi.js
// multi.js
export default (x, y) => x * y
新建app.js
import multi from './multi'
console.log('multi(3, 4) = ' + multi(3,4))
gitbash
输入 webpack app.js bundle.js
操作界面上可以看到打包成功后的chunk
(代码块)接近3kb,现在webpack-demo下新建一个index.html文件,将bundle.js引入
<script src="./bundle.js">script>
浏览器中打开html文件,在控制台可以看到
至此我们这次打包成功了。
现在我们来分析这次简单的打包,简单项目的打包盒复杂项目的打包本质上是一样的,现在我们分析简单的。
这次打包用到了两个模块 app.js
multi.js
命令行打包时指定了entry: app.js
, 和output: 'bundle.js'
打包后的bundle.js为2.96kb,比两个单独模块加起来还多了将近1kb,可能会有疑问,既然打包会使体积变大,那么为什么还要打包呢。
我们前面提到了模块化开发,实际项目中,以vue开发为例,为了代码复用和便于维护,我们会将项目中的组件分为基础组件和业务组件,各个组件都用到的js逻辑抽象为单独的js模块以提供给各个组件使用。这样可以将复杂的项目分为细小的模块,如果某个业务组件用到了基础组件和js逻辑只需要在该业务组件中引入基础组件和js模块即可。也节省了代码量和便于维护。但是这样的项目如果不打包浏览器目前是不支持的,只有打包后浏览器才能正确解析。
那么你可能会问,那么为什么还模块化开发呢?
首先为了避免重复造轮子,直接使用已经有的东西,如果不采取这种方式,你需要自己用代码在项目中实现已经有的东西,而实现这些已经有的轮子你不仅会花费时间和精力,也会是代码变得更加复杂,有时实现轮子本身的代码就很复杂,这样一比较可能代码量更大,而且不好维护。实际上一个真实项目打包后体积会大大缩小,还可以借助webpack的plugins对代码进行压缩,这样打包后的代码就更少了。这和我们上面的demo是不一样的。
上面我们打包了ES6 module,那么接下来我们来看webpack打包CommonJS实现的模块。
webpack-demo文件夹下新建arraySum.js
来计算一个数组元素中Number类型的元素之和。
// arraySum.js
module.exports = (arr) => {
let sum = 0
if (!Array.isArray(arr)) {
return
}
for (let i = 0; i < arr.length; i++ ) {
if (typeof(arr[i]) === 'number' ) {
sum += arr[i]
}
}
return sum
}
// app.js
let arrSum = require('./arraySum')
console.log('[1, 2, "3", 4]中数值的和是' + arrSum([1, 2, "3", 4]))
// git bash 执行
webpack app.js bundle.js
html文件引入打包后的bundle.js在控制台可以看到
对Common JS定义的模块打包成功。对既有ES Modules和CommonJS同时打包可以自行验证。
上面的打包没有指定配置文件,接下来我们通过指定配置文件来完成打包这样的工作。
webpack-demo 下新建webpack.conf.js
// webpack.conf.js
module.exports = {
entry: {
app: './app'
},
output: {
filename: '[name].[hash:7].js'
}
}
girt bash 执行 webpack --config webpack.conf.js
可以看到当前目录下生成了app.49062ad.js
文件,数字字母字符串是随机生成的,通过改变[hash:number]中number的值可以改变文件名长度。
在index.html文件引入app.49062ad.js
文件在控制台可以看到
需要了解的是文件名不同,命令行执行1命令也不同
配置文件名: webpack.config.js ---> webpack.config.js
配置文件名: webpack.conf.js ---> webpack --config webpack.conf.js
如果不想用hash来生成随机文件名,也可以指定输出文件名如bundle.js
上面的demo中output没有指定文件路径,会在当前文件夹下输出打包后的文件下面指定文件路径。
// webpack.conf.js
const path = require('path') //不可少
module.exports = {
entry: {
app: './app.js'
},
output: {
filename: '[name].bundle.js',
path: __dirname + '/dist'
}
}
打包后可以看到在当前目录下生成dist
目录,dist
文件夹下存放打包后的文件app.bundle.js
关于output需要注意的一点是,如果entry有多个入口起点,但输出配置只能有一个,也就是说配置文件中只能有一个output
对象,不能为多个入口起点分别配置output
.
总结,这一节我们简单的介绍了entry和output,以及如何打包js模块。更多详细内容可以参考官网地址
入口起点(Entry Points)
输出(Output)