深入浅出的webpack3入门教程
正如我们所知,HTTP/1.1存在着浏览器和服务器的连接数限制,传输多个文件会耗费大量的网络资源,并造成一定的响应延迟。
尤其是到了前端项目越来越复杂的今天,往往一个页面就包含数十甚至上百个文件,如果能有这么一款工具,它能够将这些文件(不光是Javascript文件,甚至还有CSS样式表文件、图片文件等等)统一打包压缩成一个JS文件,至少能带来以下三个好处:①请求单个页面时,只需要传输最多数个文件即可;②进行页面跳转时能重用当前页面的资源,只请求极少部分的差异性资源,甚至完全不用进行网络请求(最近十分热门的单页面应用SPA);③这种动态网站具有很高的爬虫技术门槛,直接把一些中低端爬虫人员挡在门外。
1.命令行安装
新建一个空目录作为我们项目的根目录,在这里我取名为LearnWebpack
cd E:\SourceCodeAnalysis\LearnWebpack
然后,执行下面的命令,初始化我们的node.js项目
npm init -y
接着,就是安装我们的webpack
npm i -D webpack
上面的命令中i
实际上就是我们熟悉的install
的简写,而-D
实际上就是我们熟悉的-devDependencies
的简写。
下面就要为我们的package.json
添加build
命令:
{
"scripts": {
"build": "webpack"
},
"devDependencies": {
"webpack": "^3.8.1"
}
}
※这里把删除没关系的项(如:name、license)等等都删掉了,只保留对我们后续有用的项scripts
和devDependencies
这两项)
2.JS与模块
一个js文件想要作为模块使得它能被其他模块加载和使用,必须遵循一定的语法规范。当前最新的JS模块标准书写规范就是ECMAScript Modules
(简称ES Modules
或者ESM
)。
在JS的整个发展过程中,涌现了其他的许多模块标准书写规范,如:CommonJS、AMD、ES2015的模块等等。
模块用法示例
假设我们想在main.js
中调用sub.js
定义的hello()
方法,那么使用ES Modules
,具体写法就像下面这样:
▼main.js
import {hello} from './sub';
hello();
▼sub.js
export function hello() {
alert('调用了hello方法!');
}
但是一些旧版本的浏览器(例如:IE11)就无法解析这种写法,为了上面的代码能在它们上面得以运行,就要动用我们的webpack了。
3.使用webpack处理JavaScript模块
将我们的webpack配置文件webpack.config.js
修改如下:
module.exports = {
// JavaScript主文件(作为依赖关系解析的入口 )
entry: './main.js',
// 最终输出文件的相关设置
output: {
// 保存输出文件的目录(__dirname变量的值是当前所在目录)
path: `${__dirname}/`,
// 输出文件的文件名
filename: 'bundle.js'
}
};
然后,使用下面的命令启动我们的webpack进行JS文件的编译:
npm run build
之后,在当前目录下就产生了一个新的JS文件–bundle.js,然后我们的浏览器只要单单加载这一个文件,就相当于扩展并支持了ES Modules模块加载的功能。
4.代码压缩与SourceMap
除了使得浏览器拓展并支持ES Modules模块加载功能以外,很多人使用webpack还为了实现资源的统一压缩,从而达到减少网络请求和网络请求的目的。
将我们的webpack配置文件webpack.config.js
修改如下:
const webpack = require('webpack');
module.exports = {
// JavaScript主文件(作为依赖关系解析的入口 )
entry: `./main.js`,
// 最终输出文件的相关设置
output: {
// 保存输出文件的目录(__dirname变量的值是当前所在目录)
path: `${__dirname}/build`,
// 输出文件的文件名
filename: 'bundle.js'
},
// 使得source-map功能生效
devtool: 'source-map',
plugins: [
// 进行JS文件的压缩
new webpack.optimize.UglifyJsPlugin({
// 为了方便调试,开启source-map功能
sourceMap: true
})
]
};
再次运行我们的npm run build
后,可以在bulid
目录中发现两个新生成的文件——bundle.js
和bundle.map.js
。
这次我们生成的bundle.js
的大小只有684字节,而之前没有使用Uglify而之间进行编译所得到的bundle.js
的大小是2.90KB。
5.热更新与热加载
每次修改我们的源代码,想要在浏览器上确认下效果时,都要先在命令行运行npm run build
命令,实在是十分麻烦。是否还记得,在gulp中有一项十分便利的功能——watch就可以帮助我们很好地解决这一问题。(详情可见上一篇博客)
同样地,我们的大webpack同样提供了类似的实现方案,与“lite-server、BrowserSync等等概念十分类似。
为了实现热更新与热加载,首先要安装webpack-dev-server模块,运行下面的命令:
npm i -D webpack-dev-server
修改package.json
文件以增加webpack-dev-serverwebpack-dev-server会自动帮我们重新编译文件并
的启动项:
{
"scripts": {
"build": "webpack",
"start": "webpack-dev-server"
},
"devDependencies": {
"webpack": "^3.8.1",
"webpack-dev-server": "^2.9.4"
}
}
再次修改配置文件webpack.config.js
:
module.exports = {
// JavaScript主文件(作为依赖关系解析的入口 )
entry: `./main.js`,
// 最终输出文件的相关设置
output: {
// 保存输出文件的目录(__dirname变量的值是当前所在目录)
path: `${__dirname}/build`,
// 输出文件的文件名
filename: 'bundle.js'
},
// 设置本地开发环境
// 使用浏览器访问http://localhost:8081/就可以访问build/目录下对应的资源
devServer: {
contentBase: 'build',
port: 8081
},
};
这时,你可以修改main.js
或者sub.js
文件,然后观察控制台webpack-dev-server的输出或者打开浏览器进行观察,确认是否真的实现了我们的预期效果。
6.webpack与其他编译打包系统的比较
首先声明一下,gulp和grunt一般被认为是“自动化工具”,不和webpack产生直接的竞争替代关系,更多地它们常常和webpack搭配使用,从而产生许多意想不到的效果。
下面要讨论的是与webpack定位相同的其他编译打包系统,其中知名度较高的有Browserify和RequireJS。
我们的webpack除了插件丰富、可用性高外,还使用了”Tree-shaking”(摇树优化)技术,可以实现细粒度的无用代码剔除,使得最终编译生成的文件的体积得到进一步的压缩。
而另一方面,Browserify基于的是CommonJS这种相对较旧的模块语法规范(使用的是module.exports和require()这样的写法),而且由于不支持”Tree-shaking”(摇树优化)技术,压缩效果往往不如webpack。
当然,webpack的一大优势还体现在除了JS文件外,它还可以利用相关的插件,相当简单地实现把其他格式的文件(如CSS、图像,甚至音频、字体)打包成一个JS文件的功能。