【模块化开发】之 Webpack、Rollup、Parcel
项目说明
笔记来源:拉勾教育 大前端高薪训练营
阅读建议:内容较多,建议通过左侧导航栏进行阅读
模块化打包工具解决的是前端整体的模块化,并不单指 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.js6,在 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$/, // 正则表达式,用来匹配在打包过程中遇到的文件路径// 用来指定匹配到的文件,需要去使用的 loaderuse: [ // 若配置多个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 = udocument.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.htmltitle: 'Webpack Plugin Sample', // 设置 HTML 的标题meta: { // 设置页面中的 元数据标签viewport: 'width=device-width'},// 指定模板文件,使生成的HTML文件根据模板文件进行生成template: './src/index.html'}),// 同时输出多个页面文件, 即可以添加多个 HtmlWebpackPlugin 实例// 每一个 HtmlWebpackPlugin 实例,就是用来生成一个 HTML文件的new HtmlWebpackPlugin({ // 用于生成 about.htmlfilename: '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.htmlnew 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/userstarget: '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 Mapconfig.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-mergeconst 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文件// 每个打包入口会形成独立的 chunkschunks: ['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: {// 自动提取所有公共模块到单独 bundlechunks: '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-pluginconst 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>')})
【模块化开发】之 Webpack、Rollup、Parcel相关推荐
- 模块化开发工具webpack
1.模块化开发概述 前端的js代码如何复用,怎样避免多文件之间的命名冲突,前端开发中这之类的问题如何解决,答案是模块化开发.来看看模块化开发的好处吧 创建common公共模块a.js文件 var na ...
- Vue学习Day6 插槽slot使用、编译作用域、作用域插槽、模块化开发、webpack介绍、安装
想利用暑假时间好好学习一下vue,会记录每一天的学习内容. 今天是学习vue的第6天! 起起伏伏乃人生常态,继续加油- 学习内容 1. 插槽slot slot基本使用 具名插槽slot 2. 编译作用 ...
- 前端模块化开发中webpack、npm、node、nodejs之间的关系[小白总结]
https://blog.csdn.net/AngelLover2017/article/details/84801673
- html手机模块化,jQuery 移动端拖拽(模块化开发,触摸事件,webpack)
通过jquery可以很容易实现CP端的拖拽.但是在移动端却不好用了.于是我自己写了一个在移动端的拖拽demo,主要用到的事件是触摸事件(touchstart,touchmove和touchend). ...
- 前端模块化开发学习之gulpbrowserify篇
随着web应用的发展,前端的比重占得越来越多,编写代码从而也越来越复杂.而通常我们需要将不同功能或者不同模块的代码分开写,最后在html中一起加载,这样做是可以的,但是当你需要进行维护或者是二次开发 ...
- Vue 模块化开发(构建项目常用工具)
针对刚接触 JavaScript 模块开发系统的用户 vue官方建议我们参考 Vue CLI 3.只要遵循指示,就能很快地能运行一个带有 .vue 组件.ES2015.webpack 和热重载 (ho ...
- js 多个定时器_Node.js系列深入浅出Node模块化开发——CommonJS规范
前言 本文将为大家透彻的介绍关于Node的模块化--CommonJS的一切. 看完本文可以掌握,以下几个方面: 什么是模块化,以及没有模块化会带来哪些问题,是如何解决的: JavaScript的设计缺 ...
- 为什么JavaScript需要模块化开发?
为什么需要模块化开发? 随着代码复杂程度的提高, 项目也变得越来越难维护, JavaScript模块化 也因此油然而生, 这应该是大家最熟悉的一种加载方式, 但是缺点也比较明显 所有的模块都处于全局作 ...
- 什么是前端模块化?为什么要进行模块化开发?前端技术文章分享
之前文章都分享的Java相关,今天就分享一篇前端技术文章,一起来看看今日前端技术文章吧~希望能够帮助到你! 模块化是一种软件开发的设计模式,它将一个大型的软件系统划分成多个独立的模块,每个模块都有自己 ...
- 前端面试题 ~ 有关模块化开发
1.说说你对前端模块化开发的认识. (1)异步模块定义(AMD)规范是 require. js推广的.对模块定义的规范. (2)通用模块定义(CMD)规范是 SeaJS推广的.对模块定义的规范. (3 ...
最新文章
- Linux登录那点事
- PHP 选取数组中最大的 键 和 值
- oracle adg的特点是什么,Oracle12c ADG新特性
- PtQt4标准对话框——QFileDialog
- Tailwindcss尤大神都fork了,是未来的趋势?
- linux ojvm补丁安装,打补丁PSU
- [洪流学堂]Hololens开发入门篇2之Hello World
- Python字符串count()
- php store快捷键设置,mac 下 phpstorm 快捷键整理
- ERP操作手册要不要做?
- 【转】程序员这口饭-职业规划解决方案
- dejavu歌曲识别介绍
- python回归分析
- Python 简易实现 base64 编码
- 【愚公系列】2022年07月 Go教学课程 004-Go代码注释
- 智能机器人JIMI助力用户咨询体验提升
- cyusb3014的slavefifo程序的解读
- 【python】蓄水池
- 第二届“长安杯”电子数据竞赛试题wp
- 服务器系统的监测,服务器监测系统