项目说明
笔记来源:拉勾教育 大前端高薪训练营
阅读建议:内容较多,建议通过左侧导航栏进行阅读
模块化打包工具解决的是前端整体的模块化,并不单指 JavaScript 模块化。
产生原因
- ES Modules 存在环境兼容问题;
- 模块文件过多,网络请求频繁;
- 所有的前端资源都需要模块化。
Webpack
基本介绍
webpack,常用的模块打包器(Module bundler),可以将零散的JavaScript 代码打包到一个 JS 文件中。
对于那些存在环境兼容问题的代码,可以在打包过程中通过模块加载器(Loader)对其进行编译转换。
webpack,具有代码拆分(Code Splitting)的能力,可以将所有的代码都按照需要进行打包,可以实现渐进式的打包方式。
适用场景
开发应用程序,使用 Webpack。
快速上手
-
1,准备三个文件,本次使用 http-server 构建服务器,也可以采用其他的
代码示例如下(heading.js):
export default () => { const element = document.createElement('h2') element.textContent = 'hello world' element.addEventListener('click', () => { alert('Hello webpack') }) return element }
代码示例如下(index.js):
import createHeading from './heading.js' const heading = createHeading() document.body.append(heading)
代码示例如下(index.html):
<script type="module" src="./src/index.js"></script>
-
2,webpack 是一个 NPM 工具模块,需要初始化包管理文件 package.json
$ yarn init --yes # or npm init -y
-
3,安装 webpack核心模块 ,以及对应的 webpack-cli模块
$ yarn add webpack webpack-cli --dev # or npm i webpack webpack-cli --save-dev
-
4,查看 webpack 是否安装成功
$ yarn webpack --version
运行结果,如下图所示:
-
5,使用 webpack ,进行打包
$ yarn webpack
运行结果,如下图所示:
可以看到,打包后,会生成一个 dist 文件夹,里面包含一个 main.js -
6,在 package.json 中,使用 NPM Scripts 对打包命令进行包装
配置代码如下:
{ "scripts": { "build": "webpack" } }
-
7,将 index.html 中引入的 js,进行修改
代码示例如下(index.html):
<script src="dist/main.js"></script>
基本使用
webpack 4.0+ 支持按照约定的内容,进行打包,即 src/index.js
(默认入口文件) 打包到 dist/main.js
配置文件
在项目根目录添加 webpack.config.js 配置文件。
工作模式
- development(开发模式),优化打包的速度
$ yarn webpack --mode development
- production(生产模式),启动多个插件,进行代码的压缩等
$ yarn webpack --mode production
- none,运行最原始状态的打包,不会做任何的处理
$ yarn webpack --mode none
基本配置
-
指定 webpack 打包的入口文件
配置代码如下(webpack.config.js):
module.exports = { entry: './src/main.js' // 相对路径时,./ 不能省略 }
-
设置输出文件的位置
配置代码如下(webpack.config.js):
const path = require('path') module.exports = { output: { filename: 'bundle.js', // 设置输出文件的名称 // 指定输出文件所在的目录,必须是绝对路径 // 利用 node 的 path 模块,组合生成绝对路径 path: path.join(__dirname, 'output') } }
-
配置打包的工作模式 值为:development | production | none
配置代码如下(webpack.config.js):
module.exports = { mode: 'development', }
导入资源模块
JavaScript 驱动整个前端应用的业务,因此需要把 打包入口 设置为 js 文件,它也相当于是 运行入口。在 js 代码中 通过 import 导入其他资源文件。
-
1,在 main.js 中引入 css 文件
代码示例如下(main.js):
import createHeading from './heading.js' import './main.css' const heading = createHeading() document.body.append(heading)
-
2,在 webpack.config.js 中设置入口文件
配置代码如下(webpack.config.js):
module.exports = { entry: './src/main.js' // 相对路径时,./ 不能省略 }
页面效果,如下图所示:
注意一般需要根据代码的需要动态导入资源,因为需要资源的不是应用,而是此时正在编写的代码。
优势
1)逻辑合理,JS 确实需要这些资源文件;
2)确保上线资源不缺失,都是必要的。
模块加载
webapck 进行打包过程中,会使用 loader 进行编译转换。下面,来看一下都有那些编码方式会触发对应的 loader ,并最终将其打包为 资源模块?
Js 代码
webpack 兼容多种模块化标准,但是建议不要混合使用标准
。
-
1,遵循 ES Modules 标准的 import 声明
语法代码如下:
import ... from 'module_path'
-
2,遵循 CommonJs 标准的 require 函数
语法代码如下:
require('module_path') //通过 require 函数载入 ES Modules,对于 ES Modules 的默认导出 // 需要通过导入require 结果的default 属性进行获取 const xxx = require('module_path').default
-
3,遵循 AMD 标准的 define 函数 和 require 函数
语法代码如下:
define(['module_path', 'module_path', ...], ( mod1, mod2) => { }) require(['module_path', 'module_path', ...], ( mod1, mod2) => { })
样式代码
- @import 指令 和 url 函数,会触发相应的模块加载
@import url('./reset.css'); body { background-color: url('./u0.png'); }
HTML 代码
- 图片标签的 src 属性,会触发相应的模块加载
<footer> <img src="./u0.png"> <a:href></a:href> </footer>
import footerHtml from './footer.html' document.write(footerHtml)
Loader
Loader (加载器) 是 webpack 的核心特性,借助于 Loader 就可以加载任何类型的资源,从而实现资源模块加载的功能。
webpack 内部内置的 loader 只能对 JS 文件进行打包,其他的资源文件需要引入其他的 loader 进行处理,最终都会转换成 js 模块。
Loader Kinds
编译转换类
编译转换器,会把加载到的资源模块转换为 JavaScript 代码,如 css-loader。
css-loader
css-loader,用来对 css 文件进行转换的加载器,将资源文件转换成 js 代码。
基本使用
-
1,安装 loader 模块
$ yarn add css-loader --dev # or npm i css-loader --save-dev
-
2,在 css 文件中,书写 body 的样式
样式代码如下(main.css):
body { margin: 0 auto; padding: 0 20px; max-width: 800px; background-color: #000000; }
-
3,在 webpack.config.js 中进行配置
配置代码如下(webpack.config.js):
module.exports = { entry: './src/main.css', module: { rules: [ // rules 数组,是指针对其他资源模块的加载规则的配置 { test: /.css$/, // 正则表达式,用来匹配在打包过程中遇到的文件路径 use: 'css-loader' // 用来指定匹配到的文件,需要去使用的 loader } ] } }
页面效果,如下图所示:
可以看到,此时页面中并没有对应的样式。这是因为还需要 style-loader 将转换后的结果追加到页面中。
style-loader
style-loader,用来把 css-loader 转换后的结果,通过 style 标签的形式追加到页面中。
基本使用
-
1,安装 loader 模块
$ yarn add style-loader --dev # or npm i style-loader --save-dev
-
2,修改 webpack.config.js 中的配置
配置代码如下(webpack.config.js):
module.exports = { entry: './src/main.css', module: { rules: [ // rules数组,是指针对其他资源模块的加载规则的配置 { test: /.css$/, // 正则表达式,用来匹配在打包过程中遇到的文件路径 // 用来指定匹配到的文件,需要去使用的 loader use: [ // 若配置多个loader,执行顺序是 从后往前 的 'style-loader', 'css-loader' // 先将 css 代码转换成 js 模块 ] } ] } }
babel-loader
babel-loader,用来将 ES6+ 的新特性,转换为 ES5,需要 @babel/core
核心模块,以及用于去完成具体特性转换插件的集合 @babel/preset-env
。
基本使用
-
1,安装 loader 模块
$ yarn add babel-loader @babel/core @babel/preset-env --dev
-
2,在 webpack.config.js 中添加配置规则
配置代码如下(webpack.config.js):
module.exports = { module: { rules: [ { // 通过 babel-loader 取代默认的加载器,处理代码中的新特性 test: /.js$/, use: 'babel-loader', options: { presets: ['@babel/preset-env'] } }, ] } }
总结
1)Webpack 只是 打包工具;
2)加载器可以用来编译转换代码。
html-loader
html-loader,用来处理 HTML 中制定的标签属性。
基本使用
-
1,安装 loader 模块
$ yarn add html-loader --dev
-
2,在 HTML 中编写代码
代码示例如下(footer.html):
<footer> <img src="./u0.png"> <a:href></a:href> </footer>
-
3,在 JS 文件中进行导入
代码示例如下(main.js):
import footerHtml from './footer.html' document.write(footerHtml)
-
4,在 webpack.config.js 中,添加配置
module.exports = { module: { // 针对其他资源模块的加载规则的配置 rules: [ { test: /.html$/, use: { loader: 'html-loader', options: { // 指定哪个标签属性组合应该被此 loader 处理 // 这个属性默认只有 'img:src' attrs: ['img:src', 'a:href'] } } } ] } }
文件操作类
文件操作类加载器,会把加载到的资源模块拷贝到输出的目录,同时会将文件的访问路径向外导出,如 file-loader。
file-loader
file-loader,文件资源加载器,这里主要指图片、字体等资源。
基本使用
-
1,安装 loader 模块
$ yarn add file-loader --dev # or npm i file-loader --save-dev
-
2,在 main.js 引入图片
代码示例如下(main.js):
import createHeading from './heading.js' import './main.css' import u from './u0.png' const heading = createHeading() document.body.append(heading) const img = new Image() img.src = u document.body.append(img)
-
3,在 webpack.config.js 中添加配置规则
配置代码如下(webpack.config.js):
module.exports = { output: { filename: 'main.js', path: path.join(__dirname, 'dist'), publicPath: 'dist/' // 设置网站的根目录 / 不能省略,默认为 '' }, module: { rules: [ { // 配置图片规则 test: /.png$/, use: 'file-loader' } ] } }
url-loader
url-loader,用来将资源(图片、字体等)文件转换为 Data URL 的形式,Data URLs 是一种特殊的 url 协议,url 可以直接去表示文件内容的方式,也就是说,这种 URL 中的文本就已经包含了文件内容。
在使用过程中,不会再去发送任何的 HTTP请求。如果要将图片、字体等二进制的文件进行编译时,会将文件的内容进行 base64 编码,然后以 base64编码 过后的结果(一个字符串)去表示文件的内容。
url-loader,适合转换体积比较小的文件资源。
基本使用
-
1,安装 loader 模块
$ yarn add url-loader --dev # or npm i url-loader --save-dev
-
2,在 webpack.config.js 中进行配置
配置代码如下(webpack.config.js):
module.exports = { module: { rules: [ { test: /.png$/, use: { loader: 'url-loader', options: { // 设置配置选项 limit: 10 * 1024 // 10 KB 单位字节,只匹配 10 KB 以下的 } } } ] } }
最佳实践
1)小文件使用 Data URLs,转换为 Data URLs 嵌入代码中,减少请求次数;
2)大文件单独提取存放,提高加载速度。注意
在对 url-loader 适合的文件大小进行限制后,需要同时安装 file-loader,因为超出限制的文件,会去查找 file-loader 进行转换。如果不安装 file-loader,将会因为找不到,而引起程序报错。
代码检查类
代码检查类加载器,会对所加载到的资源文件(一般指代码)去进行校验。目的是为了统一代码的风格,从而提高代码质量,这种加载器一般不会修改生产环境的代码,如 eslint-loader。
Loader Dev
开发需求
希望得到的结果是 markdown 转换过后的字符串。
准备工作
-
1,新建一个名为 markdown-loader 的项目,并创建 src 文件夹;
-
2,在 src 文件夹下,新建 xxx.md 文件,测试内容随便写;
-
3,在 src 文件夹下,新建 main.js 入口文件,并引入 xxx.md 文件
代码示例如下(main.js):
import about from './about.md' console.log(about);
-
4,在根目录下,新建 index.html,页面展示的入口文件;
-
5,初始化包管理文件 package.json
$ yarn init --yes # or npm init -y
-
6,安装 webpack 模块,以及其依赖命令模块 webpack-cli
$ yarn add webpack webpack-cli --dev # or npm i webpack webpack-cli --save-dev
-
7,在根目录下,新建 markdown-loader.js,即 md 文件的转换 loader
-
8,在根目录下,新建 webpack.config.js,并设置对 md文件的规则配置
配置代码如下(webpack.config.js):
const path = require('path') module.exports = { mode: 'none', entry: './src/main.js', output: { filename: 'bundle.js', path: path.join(__dirname, 'dist'), publicPath: 'dist/' }, module: { rules: [ { // 用来转换的 loader 既可以是一个模块,也可以是一个 js 文件 test: /.md$/, use: './markdown-loader' } ] } }
基本配置
markdown-loader.js 文件需求,输入:就是每次加载到的资源文件;输出:就是此次加工后的结果。
-
1,在 markdown-loader.js 中进行配置
配置代码如下(markdown-loader.js):
// 通过 source 参数,接收输入 module.exports = source => { console.log(source); return `console.log('hello ~')` }
可以看到,使用的 js 的代码标准进行了输出字符串,这是因为 loader 要求输出结果必须是一段标准的 JavaScript代码。
-
2,若要解析 md 文件,则需要安装 md 文件的解析模块
$ yarn add marked --dev # or npm i marked --save-dev
-
3,在 markdown-loader.js 中,使用 marked 模块解析 md 文件,并将结果以模块形式导出
配置代码如下(markdown-loader.js):
const marked = require('marked') // 导入 md 文件的解析模块 module.exports = source => { // 解析 source, 返回值是一串html字符串,即转换后的结果 const html = marked(source) // 将其结果进行导出,需要输出 JavaScript 代码 return `module.exports = ${JSON.stringify(html)}` // or // return `export default ${JSON.stringify(html)}` }
-
4,返回 html字符串,交给下一个 loader 处理
配置代码如下(markdown-loader.js):
const marked = require('marked') // 导入 md 文件的解析模块 module.exports = source => { // 解析 source, 返回值是一串html字符串,即转换后的结果 const html = marked(source) // 返回 html字符串,交给下一个 loader 处理 return html }
-
5,安装用于处理 html 加载的 loader
$ yarn add html-loader --dev # or npm i html-loader --save-dev
-
6,修改 webpack.config.js 配置文件
配置代码如下(webpack.config.js):
const path = require('path') module.exports = { mode: 'none', entry: './src/main.js', output: { filename: 'bundle.js', path: path.join(__dirname, 'dist'), publicPath: 'dist/' }, module: { rules: [ { test: /.md$/, use: [ 'html-loader', './markdown-loader' // 按照 从后往前 的顺序进行执行 ] } ] } }
Plugins
webpack plugins 可以增强 webpack 自动化能力,可以解决除了资源加载以外的其他自动化工作,例如:打包之前,自动清除 dist 目录;拷贝静态文件至输出目录;压缩输出代码等。
clean-webpack-plugin
clean-webpack-plugin,自动清除输出目录插件。
基本使用
-
1,安装插件模块
$ yarn add clean-webpack-plugin --dev
-
2,在 webpack.config.js 中,添加插件配置
配置代码如下(webpack.config.js):
// 导入 clean-webpack-plugin 插件,这个插件导出一个 CleanWebpackPlugin 成员 const { CleanWebpackPlugin } = require('clean-webpack-plugin') module.exports = { // ... plugins: [ // plugins 专门用来配置插件的属性 // 一般插件导出的都是一个类型,通过这个类型创建实例 // 然后将这个实例,放入到 plugins 数组中 new CleanWebpackPlugin() ] }
注意
plugins 属性,是一个数组,它与 module 属于同级。
html-webpack-plugin
html-webpack-plugin,自动生成 HTML 插件,不需要在手动书写 html 入口文件。
基本使用
-
1,安装插件模块
$ yarn add html-webpack-plugin --dev
-
2,在 webpack.config.js 中,导入插件,并进行配置
配置代码如下(webpack.config.js):
const path = require('path') const { CleanWebpackPlugin } = require('clean-webpack-plugin') // html-webpack-plugin 默认导出的就是一个类型,无需解构其内部成员 const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { mode: 'none', entry: './src/main.js', output: { filename: 'bundle.js', path: path.join(__dirname, 'dist'), // publicPath: 'dist/' // 自动生成 html 时,不需配置 }, plugins: [ new CleanWebpackPlugin(), // 添加 HtmlWebpackPlugin 实例对象 // 自定义输出文件内容:给构造函数传入对象参数,指定配置选项 new HtmlWebpackPlugin({ // 用于生成 index.html title: 'Webpack Plugin Sample', // 设置 HTML 的标题 meta: { // 设置页面中的 元数据标签 viewport: 'width=device-width' }, // 指定模板文件,使生成的HTML文件根据模板文件进行生成 template: './src/index.html' }), // 同时输出多个页面文件, 即可以添加多个 HtmlWebpackPlugin 实例 // 每一个 HtmlWebpackPlugin 实例,就是用来生成一个 HTML文件的 new HtmlWebpackPlugin({ // 用于生成 about.html filename: 'about.html' // 指定输出的文件名 }) ] }
copy-webpack-plugin
copy-webpack-plugin,将不需要编译转换的 静态资源文件 拷贝到输出目录,一般存放在 public 目录下。
基本使用
-
1,安装插件模块
$ yarn add copy-webpack-plugin --dev
-
2,在 webpack.config.js 中,导入插件,并进行配置
配置代码如下(webpack.config.js):
const path = require('path') const CopyWebpackPlugin = require('copy-webpack-plugin') module.exports = { // ... plugins: [ // ... // 传入 数组参数,用于指定需要去拷贝的文件路径 new CopyWebpackPlugin([ // 'public/**' // 可以是一个目录,通配符,文件路径 'public' // 表示会将 public 目录下所有文件全部拷贝到输出目录 ]) ] }
plugins dev
Plugin 是通过 在webpack 生命周期的钩子中挂载函数实现扩展的。Webpack 要求,插件必须是一个函数或者是一个包含 apply 方法的对象,最后将其挂载到 钩子上。
开发需求
删除 bundle.js 中生成的注释。
基本配置
-
在 webpack.config.js 中,进行插件的创建和使用
配置代码如下(webpack.config.js):
class MyPlugin { // 定义一个插件类型 /** * 在 webpack 启动时,自动被调用 * @param {*} compiler * compiler 对象参数,是 webpack 工作过程中最核心的一个对象 * compiler 对象参数,包含了此次构建的所有配置信息 * 通过 compiler 对象注册钩子函数 */ apply(compiler) { console.log('MyPlugin 启动'); /** * 通过 compiler.hooks 可以访问到钩子 * 通过 tap 方法去注册钩子函数 * tap方法,接收两个参数: * -- 第一个参数:插件的名称 * -- 第二个参数:需要挂载到钩子上的函数 */ compiler.hooks.emit.tap('MyPlugin', compilation => { // compilation 对象 => 可以理解为此次打包的上下文 // 所有打包的结果,都会放到 compilation 对象当中 for (const name in compilation) { // 对象中的键(属性名),代表每一个资源文件的名称 // 判断只对 js文件 进行处理 if (name.endsWith('.js')) { // assets 获取即将写入目录当中的资源文件信息 // source() 拿到对应的资源文件的内容 const contents = compilation.assets[name].source() // 使用正则替换代码中的注释 const withoutComments = contents.replace(/\/*\**\*\//g, '') // 将结果 覆盖到原有的文件中 compilation.assets[name] = { source: () => withoutComments, // 返回新内容 size: () => withoutComments.length // 返回内容的大小,必须方法 } } } }) } } module.exports = { // ... plugins: [ // ... // 应用 MyPlugin 插件 new MyPlugin() ] }
体验优化
自动编译
-
1,直接在命令行启动
watch
工作模式,监听文件变化,自动重新打包。$ yarn webpack --watch
-
2,在 package.json 中,配置 NPM Scripts
配置代码如下(package.json):
{ "scripts": { "build": "webpack --watch" } }
可以看到,开启 watch 工作模式以后,打包命令会一直处于工作状态,当文件修改后,会自动进行打包,直到手动结束 cli 命令。
自动刷新
使用 BrowserSync 启动热更新开发 Web服务器,实现自动刷新浏览器
-
1,全局安装 BrowserSync 模块
$ yarn global add browser-sync # or npm i browser-sync -g
-
2,使用命令启动 web服务器
$ browser-sync dist --files "**/*"
缺点
1)操作上太麻烦了;
2)效率上降低了。
Dev Server
Webpack Dev Server,是 Webpack 官方推出的开发工具,提供用于开发的 HTTP Server,集成了 自动编译 和 自动刷新浏览器 等功能。
版本说明
本次安装 Webpack Dev Server 版本,要求 webpack 4 版本以下。webpack 5+ 版本已经集成了 Webpack Dev Server 开发工具,无需再进行安装,直接使用 webpack server
即可开启服务。
注意
Webpack Dev Server 的版本,要比 Webpack 的版本低一级,否则无法使用。
准备工作
-
1,安装 开发工具
$ yarn add webpack-dev-server --dev
-
2,运行命令,使用 --open 自动唤醒浏览器,并打开运行地址
$ yarn webpack-dev-server --open
执行说明
1)运行时,内部自动使用 webpack 进行打包;
2)启动 HTTP Server,自动运行打包结果;
3)自动监听代码变化,自动立即重新打包;
4)打包结果不会写入到磁盘中,打包结果会暂时存放在内存中;
5)HTTP Server 会从内存中读取这些文件,然后发送给浏览器。优势
Webpack Dev Server,会减少很多磁盘读写操作,从而大大提高构建效率。
问题
Dev Server 默认只会 serve 打包输出文件,即只要是 webpack 打包输出的文件,都可以直接被访问。其他静态资源如果也需要 serve,则需要去告知 webpack。
基本配置
-
1,配置静态资源访问
配置代码如下(webpack.config.js):
const path = require('path') const { CleanWebpackPlugin } = require('clean-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin') // const CopyWebpackPlugin = require('copy-webpack-plugin') module.exports = { // 专门为 webpack-dev-server 指定的配置选项 devServer: { // 额外为开发服务器指定查找静态资源目录,可以是字符串或数组,配置一个或多个 contentBase: ['./public'] }, plugins: [ new CleanWebpackPlugin(), // 用于生成 index.html new HtmlWebpackPlugin({ title: 'Webpack Tutorials', meta: { viewport: 'width=device-width' }, template: './src/index.html' }), // 开发阶段最好不要使用这个插件 // 一般放在上线前的最后一次打包使用 // 开发阶段需要频繁的serve, 多次使用插件会影响运行效率 // new CopyWebpackPlugin(['public']) ] }
-
2,开发阶段接口跨域问题,需要配置 代理API
配置代码如下(webpack.config.js):
module.exports = { // 专门为 webpack-dev-server 指定的配置选项, 开发阶段的配置 devServer: { // 额外为开发服务器指定查找静态资源目录,可以是字符串或数组,配置一个或多个 contentBase: ['./public'], // proxy属性,用来添加代理服务配置 proxy: { /** * 每一个属性就是一个代理规则的配置 * 属性名: 需要被代理的请求路径前缀, * 即请求以哪一个地址开始,就会走对应的代理请求 * 属性值: 为这个前缀所匹配到的代理规则配置 */ '/api': { // http://localhost:8080/api/users => https://api.github.com/api/users target: 'https://api.github.com', // 代理目标 // http://localhost:8080/api/users => https://api.github.com/users // 如果代理目标地址中没有‘/api’,则需要重写代理目标地址 pathRewrite: { '^/api': '' // 以正则的形式进行匹配,以 ^ 开头 }, // 不能使用 localhost:8080 作为请求 GitHub 的主机名 // 设置改变主机名 changeOrigin: true } } } }
Source map
Source map,源代码地图,用来映射转换过后的代码与源代码之间的关系。一段转换过后的代码,通过转换过程中生成的 Source Map 文件,可以逆向得到源代码。主要用来在开发阶段进行调试和定位错误。
基本使用
-
1,引用 Source Map 的注释
//# sourceMapppingURL=jquery-3.4.3.min.map
在浏览器中,打开开发人员工具,开发人员工具加载到的 js文件最后存在上面的注释,会自动去请求 Source Map 文件,然后根据文件的内容逆向解析出对应的源代码,以便于调试。又因为存在映射关系,所以源代码中如果出现错误,就会很容易定位到源代码中错误的位置。
-
2,在 webpack.config.js中,配置 Source Map
配置代码如下(webpack.config.js):
// 其余代码省略 module.exports = { // 配置开发过程中的辅助工具, // 也就是与 Source Map 相关的一些功能配置 devtool: 'source-map', }
-
3,运行打包命令,查看 bundle.js 底部是否存在 Source Map 的注释
$ yarn webpack
查看 bundle.js 底部,如下图所示:
Webpack 对 Source Map的风格支持Webpack 目前支持 12 种不同的方式,每种方式所生成的 Source Map 效果,以及生成 Source Map 的速度都是不一样的。效果最好的,生成速度越慢;反之,生成最快的,生成的 Source Map 效果不好,几乎没有。
-
12 种方式对比,如下图所示:
eval 模式
eval() 函数,用来运行字符串中的 JavaScript 代码。默认情况下,运行的代码会运行在一个临时的虚拟机环境中,可以通过 sourceURL 来声明这段代码所属的文件路径。
基本使用
-
1,在浏览器控制台,进行测试
eval('console.log(123)//# sourceURL=./foo/bar.js')
运行示例,如下图所示:
点击./foo/bar.js,显示效果,如下图所示: -
2,在 webpack.config.js 中,进行配置
配置代码如下(webpack.config.js):
// 其余代码省略 module.exports = { // 配置开发过程中的辅助工具, // 也就是与 Source Map 相关的一些功能配置 devtool: 'eval', }
浏览器定位错误,如下图所示:
可以看到,当点击进去的时候,显示的却是打包过后的模块代码。在 eval 模式下,会将每个模块的js 代码都放到 eval() 函数中执行,在执行的字符串最后通过 sourceURL 的方式去说明所对应的文件路径,这样浏览器通过 eval 在执行代码时,就会知道代码所对应的源代码是哪一个文件,从而去定位错误所出现的文件。
总结
eval 模式下,不会生成 Source Map 文件,因此构建速度最快,但是其效果比较简单,只能知道源代码文件的名称,而不知道具体的行列信息。
模式对比
一次打包过程中,同时生成所有模式下的不同结果。
基本使用
- 1,在 webpack.config.js 中,进行配置
配置代码如下(webpack.config.js):
const HtmlWebpackPlugin = require('html-webpack-plugin')
const allModes = [
'eval',
'cheap-eval-source-map',
'cheap-module-eval-source-map',
'eval-source-map',
'cheap-source-map',
'cheap-module-source-map',
'inline-cheap-source-map',
'inline-cheap-module-source-map',
'source-map',
'inline-source-map',
'hidden-source-map',
'nosources-source-map'
]
module.exports = allModes.map(item => {
return {
devtool: item,
mode: 'none',
entry: './src/main.js',
output: {
filename: `js/${item}.js`
},
module: {
rules: [
{
test: /\.js$/,
use: {
// 辨别其中一类模式的差异
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env']
}
}
}
]
},
plugins: [
// 为每一个打包任务生成一个 HTML文件
new HtmlWebpackPlugin({
filename: `${item}.html`
})
]
}
})
-
2,使用 http-server 开启服务器
$ http-server dist
运行结果,如下图所示:
-
3,通过查看每一个 HTML 文件,得出各个模式的对比结果。
1)带有 module 的模式,不会经过 loader 的编译转换,生成的 Source Map 就是项目的源代码。而不带有 module 的模式,则是经过 babel 转换后的代码。
2)hidden-source-map,一般用在生成第三方包的时候,需要生成 Source Map 文件,但又不想在 包 中引入。
3)nosources-source-map,用在生产环境中,保护源代码不被暴露。
选择合适的 Source Map
下面是建议选择模式,应根据具体情况具体选择。
-
开发模式,选择
cheap-module-eval-source-map
1)代码每行不会超过 80 个字符;
2)代码经过 Loader 转换过后的差异较大;
3)首次打包速度慢无所谓,重写打包相对较快。 -
生产模式,选择
none
1)Source Map 会暴露源代码;
2)调试是开发阶段的事情。 -
生产模式,方便定位错误,选择 nosource-source-map
1)不会向外暴露源代码;
2)出现错误时,可以找到源代码对应的位置。
HMR
HMR(Hot Module Replacement),模块热替换,又叫模块热更新,他是 Webpack 中最强大的功能之一,它能够实现在应用运行过程中实时替换某个模块,而应用运行状态不会改变。HMR 极大程度的提高了开发者的工作效率,因此很受欢迎。
HMR ,已经集成在 webpack-dev-server 中,无需再单独安装模块。
开启 HMR
-
1,直接在命令中,使用
--hot
开启热更新$ yarn webpack-dev-server --hot
-
2,在 webpack.config.js 中,进行配置开启热更新
配置代码如下(webpack.config.js):
const webpack = require('webpack') module.exports = { mode: 'development', devServer: { hot: true }, plugins: [ // 载入 webpack 的内置插件 new webpack.HotModuleReplacementPlugin() ] }
Webpack 中的 HMR 并不可以开箱即用,他需要手动处理 JS 模块热替换逻辑。
HMR APIs
-
在 main.js 中,使用 HMR APIs 手动处理热替换
代码示例如下(main.js):
// module.hot 对象,是 HMR API 的核心对象 /** * accept(),用于注册模块更新过后的处理函数 * 第一个参数,指的是 依赖模块的路径 * 第二个参数,指的是 依赖更新过后的处理函数 */ module.hot.accept('./editor', () => { // 热替换逻辑 })
注意事项
-
1,处理 HMR 的代码报错会导致自动刷新
配置代码如下(webpack.config.js):
const webpack = require('webpack') module.exports = { devServer: { hotOnly: true // 只使用 HMR,不会 fallback 到 live reloading }, plugins: [ // 载入 webpack 的内置插件 new webpack.HotModuleReplacementPlugin() ] }
-
2,启用 HMR 的情况下,HMR API 报错
代码示例如下(main.js):
if (module.hot) { // 先判断这个对象是否存在,再进行任务的注册 module.hot.accept('./editor', () => { // 热替换逻辑 }) }
-
3,业务中添加的处理代码,会在打包过后自动移除。
环境配置
配置文件根据环境不同导出不同配置
-
在 webpack.config.js 中,进行导出配置
配置代码如下(webpack.config.js):
const webpack = require('webpack') const { CleanWebpackPlugin } = require('clean-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin') /** * 导出一个函数,在这个函数中设置所需的配置对象 * 接收两个参数, * 第一个参数 env:即 通过 cli 传递的环境名参数 * 第二个参数 argv: 指 运行 cli 过程中传递的所有参数 */ module.exports = (env, argv) => { // 设置默认模式:开发模式 const config = { mode: 'development', entry: './src/main.js', output: { filename: 'js/bundle.js' }, devtool: 'cheap-eval-module-source-map', devServer: { hot: true, contentBase: 'public' }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(png|jpe?g|gif)$/, use: { loader: 'file-loader', options: { outputPath: 'img', name: '[name].[ext]' } } } ] }, plugins: [ new HtmlWebpackPlugin({ title: 'Webpack Tutorial', template: './src/index.html' }), new webpack.HotModuleReplacementPlugin() ] } // 生产模式 if (env === 'production') { config.mode = 'production' config.devtool = false // 禁用 Source Map config.plugins = [ ...config.plugins, new CleanWebpackPlugin(), new CopyWebpackPlugin(['public']) ] } return config }
启动开发模式,默认模式为 开发模式,无需指定工作模式
$ yarn webpack
启动生产模式,使用
--env
指定工作模式$ yarn webpack --env production
注意
只适用中小型项目的配置,大型项目不适合。
不同环境对应不同配置文件
-
1,新建 webpack.common.js,用来存放 公共 配置信息
配置代码如下(webpack.common.js):
const HtmlWebpackPlugin = require('html-webpack-plugin') // 公共配置 module.exports = { entry: './src/main.js', output: { filename: 'js/bundle.js' }, module: { rules: [ { test: /\.css$/, use: [ 'style-loader', 'css-loader' ] }, { test: /\.(png|jpe?g|gif)$/, use: { loader: 'file-loader', options: { outputPath: 'img', name: '[name].[ext]' } } } ] }, plugins: [ new HtmlWebpackPlugin({ title: 'Webpack Tutorial', template: './src/index.html' }) ] }
-
2,安装 webpack-merge 模块, 合并 webpack 配置
$ yarn add webpack-merge --dev
-
3,新建 webpack.prod.js ,用来存放 生产模式 配置信息
配置代码如下(webpack.prod.js):
// 导入 webpack-merge const merge = require('webpack-merge') const { CleanWebpackPlugin } = require('clean-webpack-plugin') const CopyWebpackPlugin = require('copy-webpack-plugin') const common = require('./webpack.common') // webpack-merge模块 导出 merge(), 合并 webpack 配置 module.exports = merge(common, { mode: 'production', plugins: [ new CleanWebpackPlugin(), new CopyWebpackPlugin(['public']) ] })
-
4,新建 webpack.dev.js ,用来存放 开发模式 配置信息
配置代码如下(webpack.dev.js):
const webpack = require('webpack') const merge = require('webpack-merge') const common = require('./webpack.common') module.exports = merge(common, { mode: 'development', devtool: 'cheap-eval-module-source-map', devServer: { hot: true, contentBase: 'public' }, plugins: [ new webpack.HotModuleReplacementPlugin() ] })
-
5,运行时,可以直接使用
--config
参数指定配置文件$ yarn webpack --config webpack.prod.js
-
6,或者 在 package.json 中,配置 NPM Scripts
配置代码如下(package.json):
{ "scripts": { "dev": "webpack --config webpack.dev.js", "build": "webpack --config webpack.prod.js" } }
配置优化
DefinePlugin
DefinePlugin,为代码注入全局成员。在 production 模式下,默认启用,会为代码中注入一个 process.env.NODE_ENV
的常量。一般通过这个成员去判断当前的运行环境,从而去执行对应的操作。
基本使用
-
在 webpack.config.js 中,进行配置
配置代码如下(webpack.config.js):
const webpack = require('webpack') module.exports = { // ... plugins: [ // DefinePlugin是 webpack 的内置插件 // 构造函数接收一个对象,对象中的每一个键值都会被注入到代码中 new webpack.DefinePlugin({ // 值要求的是一个 JS代码片段 API_BASE_URL: JSON.stringify('https://api.example.com') }) ] }
Tree-shaking
Tree-shaking,摇掉 代码中未引用代码(dead-code)。在启动生产模式时,自动检测出未引用的代码,并自动将未引用代码移除,从而减少冗余代码。
Tree-shaking 并不是指某个配置选项,它是一组功能搭配使用后的优化效果,在 production 模式下自动开启。
基本使用
不使用 production 模式,其他模式下开启 Tree-shaking。
-
1,在 webpack.config.js 中,进行配置
配置代码如下(webpack.config.js):
module.exports = { // 其他代码省略 mode: 'none', // 集中配置 webpack 内部的优化功能 optimization: { // 模块只导出被使用的成员 usedExports: true, // 尽可能将所有模块合并并输出到到一个函数中 concatenateModules: true, // 压缩输出结果 minimize: true } }
Tree-shaking 前提是 ES Modules,也就是说,由 webpack 打包的代码必须使用 ES Modules。
-
2,最新的 babel-loader 默认关闭 ESM 转换,可以在 webpack.config.js 中,手动设置关闭
配置代码如下(webpack.config.js):
module.exports = { mode: 'none', module: { rules: [ { test: /\.js$/, use: { loader: 'babel-loader', options: { presets: [ // 如果 Babel 加载模块时已经转换了 ESM,则会导致 Tree Shaking 失效 // ['@babel/preset-env', { modules: 'commonjs' }] // 配置为 false,确保 preset-env 内部不会开启 ES Module 转换的插件 // ['@babel/preset-env', { modules: false }] // 使用默认配置:auto,这样 babel-loader 会自动关闭 ESM 转换 ['@babel/preset-env', { modules: 'auto' }] ] } } } ] }, optimization: { // 模块只导出被使用的成员 usedExports: true, // 尽可能合并每一个模块到一个函数中 // concatenateModules: true, // 压缩输出结果 // minimize: true } }
sideEffects
基本介绍
sideEffects,webpack 4 中新增的特性,它允许通过配置的方式去标识代码是否有副作用,从而为 Tree-shaking 提供更大的压缩空间,在 production 模式下自动开启。
副作用,是指模块执行时除了导出成员之外所做的事情。
适用场景
sideEffects,一般用于 npm 包标记是否有副作用。
前提条件
确保你的代码真的没有副作用,否则会误删掉那些有副作用的代码。
基本使用
-
1,在 webpack.config.js 中,开启sideEffects特性
配置代码如下(webpack.config.js):
module.exports = { mode: 'none', optimization: { // 手动开启特性 sideEffects: true, // 模块只导出被使用的成员 // usedExports: true, // 尽可能合并每一个模块到一个函数中 // concatenateModules: true, // 压缩输出结果 // minimize: true, } }
检查 package.json 中是否有 sideEffects 的标识,以此来判断这个模块是否有副作用。
-
2,设置所有模块都没有副作用,模块中没有被用到的代码就不会再被打包,则将会被移除掉。
配置代码如下(package.json):
{ "sideEffects": false }
-
3,设置某些模块具有副作用,即 将这些模块会被打包进输出结果,不会被移除掉。
配置代码如下(package.json):
{ "sideEffects": [ "./src/extend.js", "*.css" ] }
Code Splitting
Code Splitting,代码分包/代码分割,在应用中按需加载模块,从而提高应用的响应速度和运行效率。
多入口打包
多入口打包,一般适用于多页应用程序,即 一个页面对应一个打包入口,公共部分单独提取。
基本使用
-
1,在 webpack.config.js 中,进行配置
配置代码如下(webpack.config.js):
const { CleanWebpackPlugin } = require('clean-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin') module.exports = { mode: 'none', /** * entry 属性值的形式: * 字符串:设置一个打包入口 * 数 组: 将多个文件打包进一个文件中 * 对 象: 设置多个打包入口,分别生成对应的打包文件 * 一个属性对应一个打包入口, * 属性名为入口名称,属性值为入口所对应的文件路径 */ entry: { index: './src/index.js', album: './src/album.js' }, output: { // 多个入口,就意味着生成多个打包文件 // 使用 [name] 占位符,动态输出文件名 // [name] 最终会被替换成 入口的名称 filename: '[name].bundle.js' }, plugins: [ new CleanWebpackPlugin(), new HtmlWebpackPlugin({ title: 'Multi Entry', template: './src/index.html', filename: 'index.html', // 指定每个 HTML 文件所使用的 bundle文件 // 每个打包入口会形成独立的 chunks chunks: ['index'] }), new HtmlWebpackPlugin({ title: 'Multi Entry', template: './src/album.html', filename: 'album.html', chunks: ['album'] }) ] }
-
2,在 webpack.config.js 中,配置属性,使其在打包时自动提取公共模块
配置代码如下(webpack.config.js):
// 其余部分省略 module.exports = { optimization: { splitChunks: { // 自动提取所有公共模块到单独 bundle chunks: 'all' } }, }
动态导入
按需加载,需要用到某个模块时,再加载这个模块,可以极大的节省带宽和流量。动态导入的模块会被自动提取到对应的 bundle 中,从而实现分包。相对多入口打包,更加灵活。
基本使用
-
在需要导入的地方,使用 ES Modules 的动态导入
代码示例如下(index.js):
if (hash === '#posts') { // 魔法注释:命名 bundle 的名称,相同的名称会打包到一个 bundle 中 // /* webpackChunkName: 'components' */' import(/* webpackChunkName: 'components' */'./posts/posts').then(({ default: posts }) => { mainElement.appendChild(posts()) }) } else if (hash === '#album') { import(/* webpackChunkName: 'components' */'./album/album').then(({ default: album }) => { mainElement.appendChild(album()) }) }
MiniCssExtractPlugin
MiniCssExtractPlugin,将 CSS 代码从打包结果中提取出来的插件,通过这个插件,可以实现 CSS 的按需加载。
基本使用
-
1,安装插件模块
$ yarn add mini-css-extract-plugin --dev
-
2,在 webpack.config.js 中,进行导入和配置
配置代码如下(webpack.config.js):
// 导入 mini-css-extract-plugin 插件 const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { module: { rules: [ { test: /\.css$/, use: [ 'style-loader', // 将样式通过 style 标签注入到页面中 // 实现样式文件通过 link 标签的方式注入 MiniCssExtractPlugin.loader, 'css-loader' ] } ] }, plugins: [ // 创建 MiniCssExtractPlugin 插件实例,自动提取 CSS 到单个文件中 new MiniCssExtractPlugin() ] }
使用建议
当样式代码所占内存较小时,不建议生成单个文件,此时减少请求次数,可能效果更好。
OptimizeCssAssetsWebpackPlugin
webpack 内置的压缩插件,只针对 JS 代码,对于其他的资源文件,都要使用对应的压缩插件进行压缩。
OptimizeCssAssetsWebpackPlugin,压缩输出的 CSS 文件。
基本使用
-
1,安装插件模块
$ yarn add optimize-css-assets-webpack-plugin --dev # css 压缩插件 $ yarn add terser-webpack-plugin --dev # webpack 内置的 JS 压缩插件
-
2,在 webpack.config.js 中,进行导入和配置
配置代码如下(webpack.config.js):
const { CleanWebpackPlugin } = require('clean-webpack-plugin') const HtmlWebpackPlugin = require('html-webpack-plugin') // 导入 mini-css-extract-plugin 插件 const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 导入 optimize-css-assets-webpack-plugin const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin') // 导入 webpack 内置的 JS 压缩插件 const TerserWebpackPlugin = require('terser-webpack-plugin') module.exports = { optimization: { // 只有在 minimizer 特性开启时,才会运行其内部的插件 // 生产模式时,minimizer 特性自动开启,即下面插件才会工作 // 配置 minimizer 时,webpack 内部的压缩插件就会失效,需要手动添加 minimizer: [ new TerserWebpackPlugin(), new OptimizeCssAssetsWebpackPlugin() ] } }
substitutions
文件名使用 Hash 的原因?
一旦资源文件发生改变,文件名称也可以跟着改变。对于客户端而言,全新的文件名,就是全新的请求,则将不会存在缓存问题。也就是说,把服务端的缓存策略时间设置的非常长,就不用担心文件更新过后的问题。因此,生产模式下,文件名使用 Hash。
三种 Hash
-
1,[hash] 属于 项目级别,即项目中的任何一个地方变化,都会导致打包时,Hash值 全部改变
配置代码如下(webpack.config.js):
const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { output: { filename: '[name]-[hash].bundle.js' }, plugins: [ new MiniCssExtractPlugin({ filename: '[name]-[hash].bundle.css' }) ] }
-
2,[chunkhash] 属于 chunk 级别,即在打包中,只要是同一路的打包,chunkhash 就是相同的。相比于 [hash],控制较精确一点。
配置代码如下(webpack.config.js):
const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { output: { filename: '[name]-[chunkhash].bundle.js' }, plugins: [ new MiniCssExtractPlugin({ filename: '[name]-[chunkhash].bundle.css' }) ] }
-
3,[contenthash] 属于 文件级别,根据输出文件的内容输出 hash值,即不同的文件就有不同的hash值,最适合解决缓存问题,通过
:number
指定hash的长度。配置代码如下(webpack.config.js):
const MiniCssExtractPlugin = require('mini-css-extract-plugin') module.exports = { output: { filename: '[name]-[contenthash:8].bundle.js' }, plugins: [ new MiniCssExtractPlugin({ filename: '[name]-[contenthash].bundle.css' }) ] }
Rollup
基本介绍
Rollup,可以将项目中散落的代码打包成整块的代码,从而使得这些划分的模块,更好的运行在浏览器环境或者 NodeJs 中。相对于 Webpack 来说,Rollup 更为小巧,它仅仅是一款 ES Modules 的打包器,是一个提供充分利用 ES Modules 各项特性的高效打包器。
适用场景
开发一个框架或者类库,使用 Rollup。
快速上手
Rollup打包时,会默认开启 Tree-shaking。
基本使用
- 1,安装 Rollup 模块
$ yarn add rollup--dev
- 2,运行 Rollup 的 cli 命令,查看 rollup 各种参数
$ yarn rollup
- 3,运行命令,指定打包的入口文件、输出文件的格式,以及输出文件的路径,进行打包
$ yarn rollup ./src/index.js --format iife --file dist/bundle.js
基本使用
配置文件
在项目根目录下,新建 rollup.config.js 配置文件。
基本使用
-
1,安装 Rollup 模块
$ yarn add rollup --dev
-
2,新建 rollup.config.js 配置文件,进行打包信息的配置
配置代码如下(rollup.config.js):
// 导出一个配置对象 export default { input: 'src/index.js', // 指定打包的入口文件 // 指定输出文件的配置信息 output: { file: 'dist/bundle.js', // 指定输出文件的文件名 format: 'iife' // 指定输出文件的格式,自执行函数 } }
-
3,运行命令,通过
--config
表明使用项目中的配置文件,默认不会读取配置文件,默认读取的配置文件名称:rollup.config.js$ yarn rollup --config # [配置文件名称]
Plugins
插件是 Rollup 唯一扩展途径。
rollup-plugin-json
rollup-plugin-json,用来在代码中导入 json 文件。
基本使用
-
1,安装插件模块
$ yarn add rollup-plugin-json --dev
-
2,在 rollup.config.js 中,进行配置
配置代码如下(rollup.config.js):
// 默认导出插件函数 import json from 'rollup-plugin-json' export default { // plugins 属性,存放的是插件函数的调用结果 plugins: [ json() ] }
rollup-plugin-node-resolve
rollup-plugin-node-resolve,用来加载 NPM 模块。也就是说,可以在代码中,直接使用模块名称导入模块。
基本使用
-
1,安装插件模块
$ yarn add rollup-plugin-node-resolve --dev
-
2,在 rollup.config.js 中,进行配置
配置代码如下(rollup.config.js):
import resolve from 'rollup-plugin-node-resolve' export default { plugins: [ resolve() ] }
rollup-plugin-commonjs
rollup-plugin-commonjs,用来加载 CommonJS 模块。
基本使用
-
1,安装插件模块
$ yarn add rollup-plugin-commonjs --dev
-
2,在 rollup.config.js 中,进行配置
配置代码如下(rollup.config.js):
import commonjs from 'rollup-plugin-commonjs' export default { plugins: [ commonjs() ] }
Code Splitting
动态导入
Code Splitting,代码分包/代码分割。由于 Rollup 遵循 ES Modules,因此他可以使用 ES Modules 的动态导入实现。
基本使用
-
1,在 JS 文件中,使用 动态导入 进行模块的加载
代码示例如下(index.js):
// 返回 Promise 对象 import('./logger').then(({ log }) => { log('code splitting~') })
-
2,修改 rollup.config.js 配置文件
配置代码如下(rollup.config.js):
export default { input: 'src/index.js', output: { // file: 'dist/bundle.js', // 只能指定一个文件 // format: 'iife' dir: 'dist', // 需要输出多个文件 // iife 自执行函数,会把所有的模块放到同一个函数中,没有引导代码,无法实现代码拆分。 format: 'amd' // 浏览器环境中,遵循 AMD 标准 } }
多入口打包
类似于 webpack 中的多入口打包,配置多个入口文件,生成多个输出文件,并在打包过程中,自动将公共部分单独提取。
基本使用
-
1,在 rollup.config.js 中,配置多个入口文件,类似 webpack
配置代码如下(rollup.config.js):
export default { // input: ['src/index.js', 'src/album.js'], input: { foo: 'src/index.js', bar: 'src/album.js' }, // 多入口打包,会提取公共模块,会实行代码拆分 output: { dir: 'dist', format: 'amd' } }
-
2,手动创建 index.html ,在其中使用打包后的 JS 文件
代码示例如下(index.html):
<body> <!-- AMD 标准格式的输出 bundle 不能直接引用 --> <!-- <script src="foo.js"></script> --> <!-- 需要 Require.js 这样的库 --> <script src="https://unpkg.com/requirejs@2.3.6/require.js" data-main="foo.js"></script> </body>
优点缺点
优点
- 1,输出结果更加扁平;
- 2,自动移除未引用代码;
- 3,打包结果依然完全可读。
缺点
- 1,加载非 ESM 的第三方模块比较复杂;
- 2,模块最终都被打包到一个函数中,无法实现 HMR;
- 3,浏览器环境中,代码拆分功能依赖 AMD 库。
Parcel
Parcel,是一款完全 零配置 的前端应用打包器。相对于 Webpack 来说,构建速度要快,因为他的内部采用多进程。
基本使用
Parcel 官方建议,使用 HTML 文件作为打包入口。
-
1,安装 Parcel 打包器
$ yarn add parcel-bundler --dev
-
2,在 src 目录下,新建 index.html 文件,此文件将作为打包的入口文件
代码示例如下(index.html):
<body> <script src="main.js"></script> </body>
-
3,在 src 目录下,新建 main.js 和 foo.js 文件,作为测试文件
代码示例如下(main.js):
import foo from './foo.js' foo.bar()
代码示例如下(foo.js):
export default { bar: () => { console.log('hello parcel~'); } }
-
4,开发环境,打包命令,将 HTML 文件作为打包入口,同时开启 Web 服务器
$ yarn parcel src/index.html
-
5,生成环境,打包命令
$ yarn parcel build src/index.html
基本功能
在运行打包命令后,不仅会生成对应的打包文件,还会自动开启一个 web 服务器。
启动的web服务器,会自动监听代码的变化,从而实现自动编译,浏览器自动刷新。也就是说,不管做什么,都不用担心配置等,Parcel 会自动去实现。
测试用例
-
1,HMR(自动热替换),在 main.js 编写 热替换 逻辑
代码示例如下(main.js):
if (module.hot) { // accept() 只接收一个回调函数参数, // 作用:当前模块更新,或者其所依赖的所有模块更新过后,会自动执行 module.hot.accept(() => { // 热替换逻辑 }) }
-
2,自动安装依赖
代码示例如下(main.js):
import $ from 'jquery' $(document.body).append('<h1>Hello Parcel</h1>')
通过测试,可以知道,在引入 jquery 之后,会自动下载 jquery 的依赖包。
-
3,动态导入
代码示例如下(main.js):
import('jquery').then($ => { $(document.body).append('<h1>Hello Parcel</h1>') })