ES 模块 Lexer
JS 模块语法法 声调 - shims。 。 。 .
产出出口清单和进口规格的所在地,包括动态进出口元处理.
一个非常小的JS文件(4KiB gzipped),包括了内置的Web大会,仅用于ECMAScript模块语法的非常快的源分析.
例如,Angular 1(720KiB)完全被解析为5ms,与最快的JS解析器Arcorn相比,它占据了100ms以上.
综合处理JS语言语法,同时保持小而快. - JS冷的每 MB ~ 10 ms, JS热的每 MB ~ 5 ms, 参见基准 需要更多信息.
使用量
npm install es-module-lexer
用于通用JS:
const { init, parse } = require('es-module-lexer');
(async () => {
// either await init, or call parse asynchronously
// this is necessary for the Web Assembly boot
await init;
const source = 'export var p = 5';
const [imports, exports] = parse(source);
// Returns "p"
source.slice(exports[0].s, exports[0].e);
// Returns "p"
source.slice(exports[0].ls, exports[0].le);
})();
还提供了ES模块版本:
import { init, parse } from 'es-module-lexer';
(async () => {
await init;
const source = `
import { name } from 'mod\\u1011';
import json from './json.json' assert { type: 'json' }
export var p = 5;
export function q () {
};
export { x as 'external name' } from 'external';
// Comments provided to demonstrate edge cases
import /*comment!*/ ( 'asdf', { assert: { type: 'json' }});
import /*comment!*/.meta.asdf;
`;
const [imports, exports] = parse(source, 'optional-sourcename');
// Returns "modထ"
imports[0].n
// Returns "mod\u1011"
source.slice(imports[0].s, imports[0].e);
// "s" = start
// "e" = end
// Returns "import { name } from 'mod'"
source.slice(imports[0].ss, imports[0].se);
// "ss" = statement start
// "se" = statement end
// Returns "{ type: 'json' }"
source.slice(imports[1].a, imports[1].se);
// "a" = assert, -1 for no assertion
// Returns "external"
source.slice(imports[2].s, imports[2].e);
// Returns "p"
source.slice(exports[0].s, exports[0].e);
// Returns "p"
source.slice(exports[0].ls, exports[0].le);
// Returns "q"
source.slice(exports[1].s, exports[1].e);
// Returns "q"
source.slice(exports[1].ls, exports[1].le);
// Returns "'external name'"
source.slice(exports[2].s, exports[2].e);
// Returns -1
exports[2].ls;
// Returns -1
exports[2].le;
// Dynamic imports are indicated by imports[2].d > -1
// In this case the "d" index is the start of the dynamic import bracket
// Returns true
imports[2].d > -1;
// Returns "asdf" (only for string literal dynamic imports)
imports[2].n
// Returns "import /*comment!*/ ( 'asdf', { assert: { type: 'json' } })"
source.slice(imports[3].ss, imports[3].se);
// Returns "'asdf'"
source.slice(imports[3].s, imports[3].e);
// Returns "( 'asdf', { assert: { type: 'json' } })"
source.slice(imports[3].d, imports[3].se);
// Returns "{ assert: { type: 'json' } }"
source.slice(imports[3].a, imports[3].se - 1);
// For non-string dynamic import expressions:
// - n will be undefined
// - a is currently -1 even if there is an assertion
// - e is currently the character before the closing )
// For nested dynamic imports, the se value of the outer import is -1 as end tracking does not
// currently support nested dynamic immports
// import.meta is indicated by imports[3].d === -2
// Returns true
imports[4].d === -2;
// Returns "import /*comment!*/.meta"
source.slice(imports[4].s, imports[4].e);
// ss and se are the same for import meta
})();
CSP asm.js 构建
默认版本的库使用Wasm和(安全)eval的用法来进行性能和最小的足迹.
两者都不是安全升级的可能性,因为没有执行字符串注射向量,但这仍然可能违反现有的CSP应用政策.
对于与 CSP eval 已禁用的版本,请使用 es-module-lexer/js 构建 :
import { parse } from 'es-module-lexer/js';
而不是Web Assembly,它使用一个 Asm.js 构建,它几乎和Wasm 版本一样快(见下文基准) (中文(简体) ).
逃脱顺序
要处理指定字符串中的逃生序列 .n 尽可能提供输入的规格.
对于动态导入表达式, 如果不是一个有效的 JS 字符串, 此字段将是空的 .
外观检测
只能使用导入/导出语法的外观模块可以通过第三个返回值检测:
const [,, facade] = parse(`
export * from 'external';
import * as ns from 'external2';
export { a as b } from 'external3';
export { ns };
`);
facade === true;
环境支助
节点.js 10+,以及 所有有Web Assembly支持的浏览器。 。 。 .
语法支持
- Token状态解析出所有行注释,块注释,字符串,模板字符串,块,parens和活页符.
- 分区操作员/ regex 符号模糊是通过回溯检查处理的,包括关闭牙套或剖面回溯跟踪.
- 总是正确分析有效的JS来源,但可以毫无错误地分析无效的JS来源.
限制
制定法的方法旨在通过回溯跟踪和paren / 牙套跟踪处理包括RegEx / division 运算器在内的全部语言语法.
对已减少的参数的唯一限制是,“出口”清单可能无法正确收集以下边缘情况下的所有出口标识符:
// Only "a" is detected as an export, "q" isn't
export var a = 'asdf', q = z;
// "b" is not detected as an export
export var { a: b } = asdf;
以上案例的处理优雅,因为利克斯尔会继续完善,只是无法正确发现上面的出品名.
基准
可使用 npm run bench。 。 。 .
目前高光谱机的结果:
Wasm 构建
Module load time
> 5ms
Cold Run, All Samples
test/samples/*.js (3123 KiB)
> 18ms
Warm Runs (average of 25 runs)
test/samples/angular.js (739 KiB)
> 3ms
test/samples/angular.min.js (188 KiB)
> 1ms
test/samples/d3.js (508 KiB)
> 3ms
test/samples/d3.min.js (274 KiB)
> 2ms
test/samples/magic-string.js (35 KiB)
> 0ms
test/samples/magic-string.min.js (20 KiB)
> 0ms
test/samples/rollup.js (929 KiB)
> 4.32ms
test/samples/rollup.min.js (429 KiB)
> 2.16ms
Warm Runs, All Samples (average of 25 runs)
test/samples/*.js (3123 KiB)
> 14.16ms
JS Building (asm.js) (英语)
Module load time
> 2ms
Cold Run, All Samples
test/samples/*.js (3123 KiB)
> 34ms
Warm Runs (average of 25 runs)
test/samples/angular.js (739 KiB)
> 3ms
test/samples/angular.min.js (188 KiB)
> 1ms
test/samples/d3.js (508 KiB)
> 3ms
test/samples/d3.min.js (274 KiB)
> 2ms
test/samples/magic-string.js (35 KiB)
> 0ms
test/samples/magic-string.min.js (20 KiB)
> 0ms
test/samples/rollup.js (929 KiB)
> 5ms
test/samples/rollup.min.js (429 KiB)
> 3.04ms
Warm Runs, All Samples (average of 25 runs)
test/samples/*.js (3123 KiB)
> 17.12ms
大楼
这个项目使用 选择 用于建筑.
安装了 Chomp, 下载 WASI SDK 12.0 从 https://github.com/Web Assembly/wasi-sdk/releases/tag/wasi-sdk-12 (中文(简体) )。 。 。 .
将 WASI- SDK 定位为兄弟姐妹文件夹,或自定义路径 WASI_PATH 环境变量.
缩写 emsdk 也被认为是一个兄弟姐妹文件夹,或者通过 EMSDK_PATH 环境变量.
示例设置 :
git clone https://github.com:guybedford/es-module-lexer
git clone https://github.com/emscripten-core/emsdk
wget https://github.com/WebAssembly/wasi-sdk/releases/download/wasi-sdk-12/wasi-sdk-12.0-linux.tar.gz
gunzip wasi-sdk-12.0-linux.tar.gz
tar -xf wasi-sdk-12.0-linux.tar
mv wasi-sdk-12.0-linux.tar wasi-sdk-12.0
cargo install chompbuild
cd es-module-lexer
chomp test
给 asm.js 构建、 git 克隆 emsdk 从假设 是一个兄弟文件夹.
许可证
麻省理工学院