# ES Module技术专题
# 概述
在前端开发中,为了避免变量名中的意外冲突,同时降低代码的复杂度,提高代码的可维护性,前端技术领域逐渐发展出了模块化开发的理念,并推出了AMD(异步模块定义)、CMD(通用模块定义)、CommonJS、ES Module 等一系列模块化规范。
ES Module(以下简称:ESM)是当今 JavaScript 开发中主流的模块化规范 ,它是由 JavaScript 语言规范《ECMAScript 2015标准》(ES2015)提出的模块化方案。ESM 在语言标准的层面上实现了模块功能,语法简洁,实现简单,是浏览器和服务器通用的模块化规范。
本文将从以下几个方面对 ESM 进行详细介绍,并通过一个完整的模块化开发示例为您介绍如何在 SuperMap iClient JavaScript 中基于 ESM 实现 WebGIS 项目的开发。
- ESM 特点:ESM 在浏览器兼容性、模块加载方面的优势;
- ESM 基本语法:在 webpack 项目里使用 ESM 的基本方法;
- 模块化开发示例:基于 webpack 项目和 ESM 的 WebGIS 开发示例。
# ESM特点
ES Module 作为现代 JavaScript 开发中通用的模块化规范,具有支持静态加载、动态加载、支持主流浏览器的特点。
- 静态加载
ESM的加载方式为静态加载,在编译过程中就能确定引入和导出的变量、模块间的依赖关系,与 CommonJS 的模块采用动态加载相比,ESM 模块加载效率更高。支持在开发阶段对引入和导出模块进行代码检查,并且可以在打包阶段结合 webpack 等工具进行 tree shaking,减小代码打包体积、缩短程序运行时间。
- 动态加载
在 ES2020 后,ESM 支持使用 import() 函数动态引入模块,可以在运行时根据需求延迟加载模块,而不是在应用程序启动时一次性加载所有模块,有效地提高了应用程序的性能和响应速度。
- 浏览器兼容性
AMD、CMD、CommonJS 等模块化规范基于的是 API 规范而非 ECMA 标准,并且它们未能被主流浏览器原生支持,而 ESM 是语言层面的规范,主流的 Chrome, Edge, Safari 和 Firefox 等浏览器均支持原生的 ESM,支持 ESM 的浏览器及其版本的详细信息如下。
# ESM基本语法
本小节介绍了使用 ESM 的基本语法,包括:如何将一个文件标识为 ESM、引入模块和导出模块。
- 将文件标识为 ESM
将文件扩展名设置为
.mjs
,可将文件声明为 ESM,以确保模块文件被正确解析。 在 Node.js 中,可通过设置 package.json 中的type
属性为 module 来强制 package.json 下的所有文件使用 ESM。
{
"type": "module"
}
- 引入
使用 import
关键字将其他模块引入到当前模块中,import
关键字是静态的,只能在模块的顶层使用。
// 引入变量
import { CONSTANT, variable } from './module.js';
// 引入模块中的所有变量
import * as module from './module.js';
// 引入模块中的默认导出
import module from './module.js';
// 引入模块中的默认导出和其他变量
import module, { CONSTANT, variable } from './module.js';
如果要实现动态引入,需要使用 import()
函数。
const module = await import(pathToModule);
async function renderWidget() {
const container = document.getElementById('widget');
if (container !== null) {
const widget = await import('./widget.js');
widget.render(container);
}
}
renderWidget();
- 导出
使用 export
关键字将模块中内容导出到其他模块,可以使用 export default
关键字来进行默认导出,每个模块只能有一个默认导出。
// 导出变量
export const CONSTANT = 42;
// 默认导出
const CONSTANT = 42;
export default CONSTANT;
// 导出多个变量
const name = '张三';
const CONSTANT = 42;
export { name, CONSTANT };
// 导出所有变量
export * from './module.js';
# 模块化开发示例
本小节介绍了如何在一个 webpack 项目中,基于 ESM 引入 SuperMap iClient for Leaflet 进行模块化开发,实现功能:在浏览器中显示地图并进行矩形范围查询。
# 1.安装Node.js
开发前需要检查计算机中是否安装了 JavaScript 运行时环境 Node.js ,若未安装,可以在 Node.js 官网 中进行下载安装。Node.js 在成功安装后会附带 Node.js 的包管理器 npm。
安装完成后,打开命令提示符,输入以下命令,验证 Node.js 和 npm 是否安装成功。
node -v
npm -v
如果命令提示符中输出了 Node.js 和 npm 的版本号,说明已安装成功。
# 2.创建webpack项目
构建一个基本的 webpack 项目,用于后续的模块化开发。在命令行中输入以下命令,创建一个项目文件夹,初始化一个包管理配置文件 package.json,记录与项目有关的配置。
mkdir webpack-demo
cd webpack-demo
npm init -y
在项目根目录下,创建源代码文件夹 ./src 和项目的默认执行文件 ./src/index.js,然后为项目安装以下开发依赖。
npm install webpack@5.82.1 -D
npm install webpack-cli@5.1.1 -D
# 3.开发环境配置
为了使 webpack 项目支持 WebGIS 开发,需要引入 Leaflet 和 SuperMap iClient for Leaflet。SuperMap iClient JavaScript API 接口支持 ECMAScript 6 Promise,简化异步编程,使代码更优雅更易维护。此处引入最新版本的 SuperMap iClient for Leaflet 作为项目的运行依赖。
npm install @supermapgis/iclient-leaflet -S
# 引入CSS
在项目根目录下新建基本的 HTML 文件 index.html,在 <head>
标签中引入 Leaflet CSS 文件 和 iclient-leaflet CSS 文件。
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"/>
<link rel="stylesheet" href="https://iclient.supermap.io/dist/leaflet/iclient-leaflet.min.css"/>
# 引入模块
在 index.js 文件中,通过 ESM 的 import
关键字按需引入开发所需模块,按需引入模块可以减小项目的打包体积。
(1)安装 @supermapgis/babel-plugin-import。
npm install @supermapgis/babel-plugin-import -D
(2)在项目根目录下新建配置文件 .babelrc,添加如下配置。
{
"plugins": [
[
"@supermapgis/babel-plugin-import",
{
"libraryName": "@supermapgis/iclient-leaflet"
}
]
]
}
(3)在 index.js 文件中,引入开发所需的部分组件,此处引入的是用于实现地图显示的 TiledMapLayer
,以及实现矩形范围查询的 QueryService
和 QueryByBoundsParameters
。
import L from 'leaflet';
import {TiledMapLayer,QueryService,QueryByBoundsParameters} from '@supermapgis/iclient-leaflet';
# 4.功能实现
配置好开发环境后,在 webpack 项目中实现在浏览器中显示地图和矩形范围查询的功能。
(1)在 index.html 文件的 <body>
标签中,创建地图容器 map。
<body style="margin: 0;overflow: hidden;background: #fff;width: 100%;height:100%;position: absolute;top: 0;">
<div id="map" style="margin:0 auto;width: 100%;height: 100%"></div>
</body>
(2)在 ./src/index.js 文件中添加如下代码,实现功能:在浏览器中显示地图。此处 url
填写的是 SuperMap iServer 发布的地图服务 map-world 中地图 世界地图_矢量 的服务地址。
const url = 'https://iserver.supermap.io/iserver/services/map-world/rest/maps/World';
const map = L.map('map', {
preferCanvas: true,
crs: L.CRS.EPSG4326,
center: {lon: 0, lat: 0},
maxZoom: 18,
zoom: 2
});
new TiledMapLayer(url).addTo(map);
(3)在 ./src/index.js 文件中继续添加如下代码,实现功能:查询地图服务中指定矩形范围内的要素。
function query() {
const polygon = L.polygon([[0, 0], [39, 0], [39, 60], [0, 60], [0, 0]]);
polygon.addTo(map);
const param = new QueryByBoundsParameters({
queryParams: { name: 'Capitals@World.1' },
bounds: polygon.getBounds(),
});
new QueryService(url).queryByBounds(param, function (serviceResult) {
const result = serviceResult.result;
L.geoJSON(result.recordsets[0].features).addTo(map);
});
};
query();
(4)执行 webpack 命令打包项目,在项目根目录下会生成 dist 文件夹和里面的 main.js 文件,将 main.js 文件引入 index.html 文件中。
<body style="margin: 0;overflow: hidden;background: #fff;width: 100%;height:100%;position: absolute;top: 0;">
<script src="../dist/main.js"></script>
</body>
(5)在浏览器中打开 index.html 文件,浏览器中将显示如下图所示的地图和矩形范围查询结果。
至此,您已经基于 ESM 构建了一个可用于 WebGIS 开发的 webpack 项目!更多有关 ESM 的介绍和使用方法可参考:webpack | 概念 | 模块 (opens new window)。