【云+社区年度征文】webpack 学习笔记系列02-模块化开发

Write By CS逍遥剑仙 我的主页: www.csxiaoyao.com GitHub: github.com/csxiaoyaojianxian Email: sunjianfeng@csxiaoyao.com

1. 模块化规范

三大 JavaScript 主流模块规范:CommonJS、AMD 和 ES6 Module。CommonJSAMD 都未统一浏览器和客户端的模块化规范。目前 Node.js 使用 CommonJS 作为官方的模块解决方案,虽然内置的模块方案促进了 Node.js 的流行,但是也为引入新的 ES Modules(ESM)标准造成了一定的阻碍,不过 Node.js 9.0+ 已经支持 ESM 语法。

2. CommonJS

CommonJS 规范是 JavaScript 中最常见的模块格式规范,从 2009 年提出后起先主要应用在 Node.js 服务端中,由于依赖了 Node.js 如文件系统等功能的实现,导致在浏览器环境无法使用。随着 Browserify 和 Webpack 等打包工具的崛起,通过处理的 CommonJS 前端代码也可以在浏览器中使用。

// sayhi.js
var hi = 'hello world';
function sayHi() {
    return hi;
}
module.exports = sayHi;

// index.js
var sayHi = require('./sayhi.js');
console.log(sayHi());

CommonJS 的语法,使用 require 导入模块,使用 module.exports 导出模块,在 Node.js 中会被处理为以下代码:

(function(exports, require, module, __filename, __dirname) {
    // ...
    // 模块的代码在这里
    // ...
});

3. AMD

AMD 规范最早随 RequireJS 发展而提出,是在 CommonJS 规范之后推出的一个解决 web 页面动态异步加载 JavaScript 的规范,其浏览器内支持、实现简单且支持异步加载。AMD 的语法,最核心的是两个方法:require() 引入其他模块,define() 定义新的模块。

// sayhi.js
define(function() {
    var hi = 'hello world';
    return function sayHi() {
        return hi;
    };
});

// index.js
// 依赖前置
require(['./sayhi.js'], function(sayHi) {
    console.log(sayHi());
});

AMD 模式很适合浏览器端的开发,后续有很多变种规范相继提出,如国内 Sea.js 的 CMD,还有兼容 CommonJS 和 AMD 的 UMD 规范(Universal Module Definition),随着 npm 的流行逐渐被取代。

4. ES6 Module

又称 ES2015 modules,是 ES2015 标准提出来的一种 ES 标准模块加载方式。作为 ECMAScript 官方方案,不仅在 Web 现代浏览器上得到实现,也在 Node.js 9+ 版本得到原生支持。

// sayhi.js
const hi = 'hello world';
export default function sayHi() {
    return hi;
}

// index.js
import sayHi from './sayhi';
console.log(sayHi());

5. webpack 对 Module 的增强

在 webpack 中,一切皆模块,而且可以在一个文件中混合使用 CommonJS 、AMD 和 ES6 Module 三种规范,还可以使用 webpack 对 Module 的增强方法和属性。

5.1 import() 动态加载模块

webpack 中可以通过 import('path/to/module') 的方式引入一个模块,类似 require,返回一个 Promise 对象。

import('path/to/module').then(mod => {
    console.log(mod);
});

import from 是静态分析打包语法,而 import() 是动态打包语法,可以通过异步的方式加载进来。

5.2 Magic Comments 神奇注释

在 import() 参数中可以添加指定的注释,称为神奇注释,如下面打包后的结果原本应为 main.js 和 0.js 两个文件,添加 webpackChunkName 注释后 0.js 变成了 my-chunk-name.js。通过神奇注释,import() 不再是简单的 JavaScript 异步加载器,还是任意模块资源的加载器。

import hello from './hello';
import(
    /* webpackInclude: /\.json$/ */
    /* webpackExclude: /\.noimport\.json$/ */
    /* webpackChunkName: "my-chunk-name" */
    /* webpackMode: "lazy" */
    /* webpackPrefetch: true */
    /* webpackPreload: true */
    `./locale/${language}`
).then(lazy => {
    console.log(lazy);
});

5.2.1 基础神奇注释

webpackIgnore:true 将不能动态导入

webpackChunkName:chunk 文件的名称,如 "my-chunk-name-index-request",支持占位符,index 为递增数字,request 为实际解析的文件名

webpackInclude:在导入期间这个正则表达式会用于匹配,只有被匹配到的模块才会被打包

webpackExclude:在导入期间这个正则表达式会用于匹配,被匹配到的模块不会被打包

5.2.2 神奇注释之 webpackMode

webpackMode 可以用于设置 chunk 的生成方式,可选值有:lazy / lazy-once / eager / weak。

针对 webpackMode 可选值说明如下:

lazy:默认,为每个 import() 导入的模块生成一个可延迟加载的 chunk

lazy-once:只生成一个满足所有 import() 调用的懒加载chunk,在第一次调用 import() 时就会去获取 chunk,之后调用 import() 会使用相同的网络响应。注意这只在部分动态语句中才有意义,例如:import(./locales/${language}.json),将为 locales 目录下所有模块共同创建一个异步 chunk

eager:阻止生成额外的 chunk,返回 Promise 的 resolve 状态。和静态导入不同的是,直到调用 import() 完成,module 才会被执行

weak:彻底阻止额外的网络请求,只有当该模块已在其他地方被加载过了之后,Promise 才被 resolve,否则直接 reject

5.2.3 神奇注释之 prefetch & preload

webpack4.6+支持配置 预先拉取预先加载

webpackPrefetch:是否预取模块,可选值 true(优先级0) 或整数优先级别,使用预先拉取则表示该模块可能以后会用到,浏览器会在空闲时间下载该模块,且下载是发生在父级chunk加载完成之后。

<!-- 被添加至页面头部,浏览器会在空闲时间预先拉取该文件 -->
<link rel="prefetch" as="script" href="my-chunk-name.js">

webpackPreload:是否预加载模块,可选值 true(优先级0) 或整数优先级别,使用预先加载则表示该模块需要立即被使用,异步chunk 会和 父级chunk 并行加载。若父级chunk先下载好,页面就已可显示了,同时等待异步chunk的下载,这能大幅提升性能。注意,不当地使用wepbackPreload会损害性能,所以使用时要小心。

<link rel="preload" as="script" href="my-chunk-name.js">

注意:prefetch 和 preload 都可以用于提前加载图片、样式等资源,但 prefetch 优先级低于 preload,preload 会并行或在主文件加载完后立即加载,而 prefetch 则会在主文件加载完后的空闲时间加载

5.3 require.resolve() / require.resolveWeak() 获取模块ID

都可以获取模块的唯一 ID(moduleId),区别在于 require.resolve(dependency: String) 会把模块真实引入进 bundle,而 require.resolveWeak() 则不会。配合 require.cache__webpack_modules__ 可判断模块是否加载成功或是否可用。

// in file.js
module.id === require.resolve("./file.js")

5.4 require.context() 批量加载

require.context(directory, includeSubdirs, filter) 可以批量将 directory 内的文件全部引入进文件,并且返回一个具有 resolve 的 context 对象,使用 context.resolve(moduleId) 则返回对应的模块。

参数说明: directory: 目录 string includeSubdirs: 是否包含子目录,可选,默认 true filter: 过滤正则规则,可选项

5.5 require.include()

require.include(dependency) 顾名思义为引入某个依赖,但并不执行它,可以用于优化 chunk。

// 当前 hello.js 独立为一个 chunk,若不使用 include,会被打包进 weak.js 和 lazy.js
require.include('./hello.js');
require.ensure(['./hello.js', './weak.js'], function(require) {
    /* ... */
});
require.ensure(['./hello.js', './lazy.js'], function(require) {
    /* ... */
});

5.6 __resourceQuery

当前模块的资源查询(resource query),即当前模块引入是传入的 query 信息。

// main.js
const component = require('./component-loader?param=demo');
// component-loader.js
const querystring = require('querystring');
const query = querystring.parse(__resourceQuery.slice(1)); // 去掉? 
console.log(query); // {param: demo}

5.7 其他

webpack_public_path:等同于 output.publicPath

webpack_require:原始 require 函数,这个表达式不会被解析器解析为依赖

webpack_chunk_load:内部 chunk 载入函数,__webpack_chunk_load__(chunkId, callback(require))

webpack_modules:所有模块的内部对象,可以通过传入 moduleId 来获取对应的模块

module.hot:用于判断是否在 hotModuleReplace 模式下

webpack_hash:提供对编译过程中(compilation)的 hash 信息的获取

non_webpack_require:生成一个不会被 webpack 解析的 require 函数

6. webpack 资源模块化处理

6.1 css 中 @import

css(less、sass…)可以通过 @import 的方式引入样式资源。

@import 'vars.less';
body {
    background: @bg-color;
}

6.2 js 中 import

此时样式资源文件可作为模块在 js 中引入。

import styles from './style.css';

6.3 使用 loader 把资源作为模块引入

const html = require('html-loader!./loader.html');
console.log(html);

image.png

原文地址:https://cloud.tencent.com/developer/article/1764267

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


学习编程是顺着互联网的发展潮流,是一件好事。新手如何学习编程?其实不难,不过在学习编程之前你得先了解你的目的是什么?这个很重要,因为目的决定你的发展方向、决定你的发展速度。
IT行业是什么工作做什么?IT行业的工作有:产品策划类、页面设计类、前端与移动、开发与测试、营销推广类、数据运营类、运营维护类、游戏相关类等,根据不同的分类下面有细分了不同的岗位。
女生学Java好就业吗?女生适合学Java编程吗?目前有不少女生学习Java开发,但要结合自身的情况,先了解自己适不适合去学习Java,不要盲目的选择不适合自己的Java培训班进行学习。只要肯下功夫钻研,多看、多想、多练
Can’t connect to local MySQL server through socket \'/var/lib/mysql/mysql.sock问题 1.进入mysql路径
oracle基本命令 一、登录操作 1.管理员登录 # 管理员登录 sqlplus / as sysdba 2.普通用户登录
一、背景 因为项目中需要通北京网络,所以需要连vpn,但是服务器有时候会断掉,所以写个shell脚本每五分钟去判断是否连接,于是就有下面的shell脚本。
BETWEEN 操作符选取介于两个值之间的数据范围内的值。这些值可以是数值、文本或者日期。
假如你已经使用过苹果开发者中心上架app,你肯定知道在苹果开发者中心的web界面,无法直接提交ipa文件,而是需要使用第三方工具,将ipa文件上传到构建版本,开...
下面的 SQL 语句指定了两个别名,一个是 name 列的别名,一个是 country 列的别名。**提示:**如果列名称包含空格,要求使用双引号或方括号:
在使用H5混合开发的app打包后,需要将ipa文件上传到appstore进行发布,就需要去苹果开发者中心进行发布。​
+----+--------------+---------------------------+-------+---------+
数组的声明并不是声明一个个单独的变量,比如 number0、number1、...、number99,而是声明一个数组变量,比如 numbers,然后使用 nu...
第一步:到appuploader官网下载辅助工具和iCloud驱动,使用前面创建的AppID登录。
如需删除表中的列,请使用下面的语法(请注意,某些数据库系统不允许这种在数据库表中删除列的方式):
前不久在制作win11pe,制作了一版,1.26GB,太大了,不满意,想再裁剪下,发现这次dism mount正常,commit或discard巨慢,以前都很快...
赛门铁克各个版本概览:https://knowledge.broadcom.com/external/article?legacyId=tech163829
实测Python 3.6.6用pip 21.3.1,再高就报错了,Python 3.10.7用pip 22.3.1是可以的
Broadcom Corporation (博通公司,股票代号AVGO)是全球领先的有线和无线通信半导体公司。其产品实现向家庭、 办公室和移动环境以及在这些环境...
发现个问题,server2016上安装了c4d这些版本,低版本的正常显示窗格,但红色圈出的高版本c4d打开后不显示窗格,
TAT:https://cloud.tencent.com/document/product/1340