Webpack ——开源JS打包工具,主要实现模块打包。
引言:
在Web开发中打交道的无非 是HTML、CSS、JS等静态资源,为什么不直接将工程中的源文件发布到服务器或者CDN上,而要交给Webpack处理呢?两者之间有什么不同?本文将从 为什么需要Webpack 以及简单的应用安装初步打包 进行介绍。
一、为什么需要Webpack?
1.1 模块
首先,我们要熟悉一个名词【模块】(在工程中引入一个日期处理的npm包,或者编写一个提供工具方法的JS文件,都可称为模块)。
【模块】
将所有代码按照特定的功能将其拆分成多个代码段,每个代码段实现特定的一个目的。
【模块化思想】
将每个代码段进行独立的设计、开发和测试,最终通过接口来将它们组合在一起。
1.2 历史延伸
早期的JS中并没有模块的概念,这是由于早期JS的设计者(JavaScript之父Brendan Eich)仅仅将其定位为一个小型的脚本语言,用于实现网页的简单动态特性,并未考虑到会实现今天这样复杂的场景。早期无模块化时,使用引入多个script文件到页面中实现。
【无模块化的缺点】
- 需要手动维护JS的加载顺序。页面中的多个script之间通常会存在依赖关系,但是这种关系是隐式的,除了添加注释以外很难清晰地指明谁依赖谁,这样当页面加载多个文件时容易出现问题。
- 多次请求静态资源,拖慢网页渲染速度。每个script标签意味着要向服务器请求一次静态资源,在没有HTTP2的时期,建立连接的成本很高,过多的请求会严重拖慢页面的渲染速度。
- 会造成全局作用域污染。在每个script标签中,顶层作用域就是全局作用域,如果没有任何处理而直接在代码中进行变量或函数的声明,就会造成全局作用域的污染。
【模块化改进后的优势】
- 通过导入导出语句可以清晰的看到模块间的依赖关系。
- 模块可以借助工具打包,在页面中只需要加载合并后的资源文件,减少了网络开销。
- 多个模块之间的作用域是隔离的,彼此不会有命名冲突。
1.3 为何选择Webpack
模块打包工具:用于解决模块间的依赖,使其打包后的结果可以在浏览器中正常运行。
【模块打包工具分类】
- 根据存在的依赖关系按照特定的规则将代码合并成单个JS文件,一次全部加载进页面中。
- 在页面初始时加载一个入口模块,其他模块异步地进行加载。
【Webpack的优势】
- 默认支持多种模块标准。对于同时使用多种模块标准的工程,webpack会帮我处理好不同类型模块之间的依赖关系。
- 有完备的代码分割(code splitting)解决方案。可以分割打包后的资源,首屏渲染速度快,只需要加载部分资源。
- 能够支持处理各种类型的资源 。开发者仅需要导入即可,webpack将利用loader处理。
- 拥有庞大良好的社区支持。除了Webpack核心库以外,在社区里无数开发者为它编写周边插件和工具。
二、安装 & 打包第一个应用
2.1 安装
- 需要准备node.js(有依赖关系-推荐使用长期维护版本)、npm(node的包管理器)
- 安装webpack命令
npm install webpack webpack-cli --save-dev
- 全局安装
2.2 打包第一个应用
【前置准备】
import addContent from './add-content.js';
document.write('My first Webpack app.<br />');
addContent();
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<title>Forever God.</title>
</head>
<body>
<script src="../dist/bundle.js"></script>
</body>
</html>
export default function() {
document.write('Hello World, I am xxx');
}
【本地命令行打包】
npx webpack --entry=./index.js --output-filename=bundle.js --mode=development
该命令中包含输入输出的文件名、打包模式(development、production、none),执行后本地会生成一个 【dist】文件夹,下面多了一个bundle.js文件。
【使用npm scripts 辅助打包】
scripts是npm提供的脚本命令功能,可以直接使用由模块所添加的指令代码直接输入命令行。
在package.json中添加脚本命令,可以通过使用【npm run build 】来执行打包。
......
"scripts": {
"build": "webpack --entry=./index.js --output-filename=bundle.js --mode=development",
},
......
【使用webpack.config.js 配置文件打包】
- 目录配置:工程源代码放在源码目录【/src】下;输出资源放在资源输出目录【/dist】下。
webpack 默认的源代码入口就是/src/index.js下,因此可以省掉entry的配置。
......
"scripts": {
"build": "webpack --output-filename=bundle.js --mode=development",
},
......
- 配置文件
由于webpack拥有非常多的配置项以及对应的命令行参数,可以通过【npx webpack -h】来查看。
为了避免太多的参数后期不好维护,我们将这些参改为对象的形式专门放在一个配置文件里,在每次Webpack打包的时候读取该配置文件即可。
在工程根目录下创建webpack.config.js文件
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js'
},
mode: 'development',
}
同时可以简化package.json 内的build 命令。
......
"scripts": {
"build": "webpack",
},
......
【webpack-dev-server】
以上我们完成了对Webpack的初始环境配置,但是我们发现每次修改都需要重新执行打包命令,更新bundle.js 效率并不高。
webpack开发每次都会生成bundle.js,而webpack-dev-server只是讲打包结果放在内存中,并不会写入实际的bundle.js,在每次webpack-dev-server接收到请求时都只是将内存中的打包结果返回给浏览器。
因此webpack社区为我们提供了一个便捷的本地开发工具 【webpack-dev-server】
【便捷特性:live-reloading(自动刷新)-可以监听文件变化,自动刷新页面来提升开发效率】
npm install webpack-dev-server --save-dev
--save-dev 是将webpack-dev-server作为工程的devDependencies(开发环境依赖)记录在package.json中,这样做是因为其仅在本地开发会用到,生产环境中并不需要。
......
"scripts": {
"build": "webpack --output-filename=bundle.js --mode=development",
"dev": "webpack-dev-server"
},
......
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js'
},
mode: 'development',
// 专门存在webpack-dev-server的配置
devServer: {
publicPath: './dist',
hot: true,
port: 3001
}
}
webpack-dev-server 两大职能
- 令webpack进行模块打包,并处理打包结果的资源请求;
-
作为普通的web server,处理静态资源文件请求。
-