精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

又一個基于 Esbuild 的神器!

開發(fā) 開發(fā)工具
本文的主角是由 antfu 大佬開源的 esno 項目,接下來我將帶大家一起來揭開這個項目背后的秘密。

Node.js 并不支持直接執(zhí)行 TS 文件,如果要執(zhí)行 TS 文件的話,我們就可以借助 ts-node 這個庫。相信有些小伙伴在工作中也用過這個庫,關(guān)于 ts-node 這個庫的相關(guān)內(nèi)容我就不展開介紹了,因為本文的主角是由 antfu 大佬開源的 esno 項目,接下來我將帶大家一起來揭開這個項目背后的秘密。

閱讀完本文后,你將了解 esno 項目是如何執(zhí)行 TS 文件。此外,你還會了解如何劫持 Node.js 的 require 函數(shù)、如何為 ES Module 的 import 語句添加鉤子及如何自定義 https 加載器,以支持 import React from "https://esm.sh/react" 導(dǎo)入方式。

esno 是什么

esno 是基于 esbuild 的 TS/ESNext node 運(yùn)行時。該庫會針對不同的模塊化標(biāo)準(zhǔn),采用不同的方案:

  • esno - Node in CJS mode - by esbuild-register
  • esmo - Node in ESM mode - by esbuild-node-loader

使用 esno 的方式很簡單,你可以以全局或局部的方式來安裝它:

全局安裝

$ npm i -g esno

在安裝成功后,你就可以通過以下方式來直接執(zhí)行 TS 文件:

$ esno index.ts
$ esmo index.ts

局部安裝

$ npm i esno

而對于局部安裝的方式來說,一般情況下,我們會以 npm scripts 的方式來使用它:

{
"scripts": {
"start": "esno index.ts"
},
"dependencies": {
"esno": "0.14.0"
}
}

esno 是如何工作的

在開始分析 esno 的工作原理之前,我們先來熟悉一下該項目:

├── LICENSE
├── README.md
├── esmo.mjs
├── esno.js
├── package.json
├── pnpm-lock.yaml
├── publish.ts
└── tsconfig.json

觀察以上的項目結(jié)構(gòu)可知,該項目并不會復(fù)雜。在項目根目錄下的 package.json 文件中,我們看到了前面介紹的 esno 和 esmo 命令。

{
"bin": {
"esno": "esno.js",
"esmo": "esmo.mjs"
},
}

此外,在 package.json 的 scripts 字段中,我們發(fā)現(xiàn)了 release 命令。顧名思義,該命令用來發(fā)布版本。

{
"scripts": {
"release": "npx bumpp --tag --commit --push && node esmo.mjs publish.ts"
},
}

需要注意的是,在 publish.ts 文件中,使用到了 2021 年度 Github 上最耀眼的項目 zx,利用該項目我們可以輕松地編寫命令行腳本。寫作本文時,它的 Star 數(shù)已經(jīng)高達(dá) 27.5K,強(qiáng)烈推薦感興趣的小伙伴關(guān)注一下該項目。

簡單介紹了 esno 項目之后,接下來我們來分析 esno.js 文件:

#!/usr/bin/env node

const spawn = require('cross-spawn')
const spawnSync = spawn.sync

const register = require.resolve('esbuild-register')

const argv = process.argv.slice(2)

process.exit(spawnSync('node', ['-r', register, ...argv],
{ stdio: 'inherit' }).status)

由以上代碼可知,當(dāng)執(zhí)行 esno index.ts 命令后,會通過 spawnSync 來啟動 Node.js 程序執(zhí)行腳本。需要注意的是,在執(zhí)行時使用了 -r 選項,該選項的作用是預(yù)加載模塊:

-r, --require = ... module to preload (option can be repeated)

這里預(yù)加載的模塊是 esbuild-register,該模塊就是 esno 命令執(zhí)行 TS 文件的幕后英雄。

esbuild-register 是什么

esbuild-register 是一個基于 esbuild 來轉(zhuǎn)換 JSX、TS 和 esnext 特性的工具。你可以通過以下多種方式來安裝它:

$ npm i esbuild esbuild-register -D
# Or Yarn
$ yarn add esbuild esbuild-register --dev
# Or pnpm
$ pnpm add esbuild esbuild-register -D

在成功安裝該模塊之后,就可以在命令行中,直接通過 node 應(yīng)用程序來執(zhí)行 ts 文件:

$ node -r esbuild-register file.ts

-r, --require = ... module to preload (option can be repeated)

-r 用于指定預(yù)加載的文件,即在執(zhí)行 file.ts 文件前,提前加載 esbuild-register 模塊

它將會使用 tsconfig.json 中的 jsxFactory,jsxFragmentFactory 和 target 配置項來執(zhí)行轉(zhuǎn)換操作。

esbuild-register 不僅可以在命令行中使用,而且還可以通過 API 的方式進(jìn)行使用:

const { register } = require('esbuild-register/dist/node')

const { unregister } = register({
// ...options
})

// Unregister the require hook if you don't need it anymore
unregister()

了解完 esbuild-register 的基本使用之后,接下來我們來分析它內(nèi)部是如何工作的。

esbuild-register 是如何工作的

esbuild-register 內(nèi)部利用了 pirates 這個庫來劫持 Node.js 的 require 函數(shù),從而讓你可以在命令行中,直接執(zhí)行 ts 文件。下面我們來看一下 esbuild-register 模塊中定義的 register 函數(shù):

// esbuild-register/src/node.ts
import { transformSync, TransformOptions } from 'esbuild'
import { addHook } from 'pirates'

export function register(esbuildOptions: RegisterOptions = {}) {
const {
extensions = DEFAULT_EXTENSIONS,
hookIgnoreNodeModules = true,
hookMatcher,
...overrides
} = esbuildOptions

// 利用 transformSync
const compile: COMPILE = function compile(code, filename, format) {
const dir = dirname(filename)
const options = getOptions(dir)
format = format ?? inferPackageFormat(dir, filename)

const {
code: js,
warnings,
map: jsSourceMap,
} = transformSync(code, {
sourcefile: filename,
sourcemap: 'both',
loader: getLoader(filename),
target: options.target,
jsxFactory: options.jsxFactory,
jsxFragment: options.jsxFragment,
format,
...overrides,
})
// 省略部分代碼
}

const revert = addHook(compile, {
exts: extensions,
ignoreNodeModules: hookIgnoreNodeModules,
matcher: hookMatcher,
})

return {
unregister() {
revert()
},
}
}

觀察以上的代碼可知,在 register 函數(shù)內(nèi)部是利用 esbuild 模塊提供的 transformSync API 來實現(xiàn) ts -> js 代碼的轉(zhuǎn)換。其實最關(guān)鍵的環(huán)節(jié),還是通過調(diào)用 pirates 這個庫提供的 addHook 函數(shù)來注冊編譯 ts 文件的鉤子。那么 addHook 函數(shù)內(nèi)部到底做了哪些處理呢?下面我們來看一下它的實現(xiàn):

// pirates-4.0.5/src/index.js
export function addHook(hook, opts = {}) {
let reverted = false;
const loaders = []; // 存放新的loader
const oldLoaders = []; // 存放舊的loader
let exts;

const originalJSLoader = Module._extensions['.js']; // 原始的JS Loader
// 省略部分代碼
exts.forEach((ext) => {
// 獲取已注冊的loader,若未找到,則默認(rèn)使用JS Loader
const oldLoader = Module._extensions[ext] || originalJSLoader;
oldLoaders[ext] = Module._extensions[ext];

loaders[ext] = Module._extensions[ext] = function newLoader(
mod, filename) {
let compile;
if (!reverted) {
if (shouldCompile(filename, exts, matcher, ignoreNodeModules)) {
compile = mod._compile;
mod._compile = function _compile(code) {
// 這里需要恢復(fù)成原來的_compile函數(shù),否則會出現(xiàn)死循環(huán)
mod._compile = compile;
// 在編譯前先執(zhí)行用戶自定義的hook函數(shù)
const newCode = hook(code, filename);
if (typeof newCode !== 'string') {
throw new Error(HOOK_RETURNED_NOTHING_ERROR_MESSAGE);
}

return mod._compile(newCode, filename);
};
}
}

oldLoader(mod, filename);
};
});
}

其實 addHook 函數(shù)的實現(xiàn)并不會復(fù)雜,該函數(shù)內(nèi)部就是通過替換 mod._compile 方法來實現(xiàn)鉤子的功能。即在調(diào)用原始的 mod._compile 方法進(jìn)行編譯前,會先調(diào)用 hook(code, filename)函數(shù)來執(zhí)行用戶自定義的 hook 函數(shù),從而對代碼進(jìn)行預(yù)處理。

而對于 esbuild-register 庫中的 register 函數(shù)來說,當(dāng) hook 函數(shù)執(zhí)行時,就會調(diào)用該函數(shù)內(nèi)部定義的 compile 函數(shù)來編譯 ts 代碼,然后再調(diào)用mod._compile 方法編譯生成的 js 代碼。

關(guān)于 esbuild-register 和 pirates 這兩個庫的內(nèi)容就先介紹到這里,如果你想詳細(xì)了解 pirates 這個庫是如何工作的,可以閱讀 如何為 Node.js 的 require 函數(shù)添加鉤子? 這篇文章。

現(xiàn)在我們已經(jīng)分析完 esno.js 文件,接下來我們來分析 esmo.mjs 文件。

esmo 是如何工作的

esmo 命令對應(yīng)的是 esmo.mjs 文件:

#!/usr/bin/env node

import spawn from 'cross-spawn'
import { resolve } from 'import-meta-resolve'
const spawnSync = spawn.sync

const argv = process.argv.slice(2)
resolve('esbuild-node-loader', import.meta.url).then((path) => {
process.exit(spawnSync('node', ['--loader', path, ...argv],
{ stdio: 'inherit' }).status)
})

由以上代碼可知,當(dāng)使用 node 應(yīng)用程序執(zhí)行 ES Module 文件時,會通過 --loader 選項來指定自定義的 ES Module 加載器。

--loader, --experimental-loader = ... use the specified module as a custom loader

需要注意的是,通過 --loader 選項指定的自定義加載器只適用于 ES Module 的 import 調(diào)用,并不適用于 CommonJS 的 require 調(diào)用。

那么自定義加載器有什么作用呢?在當(dāng)前最新的 Node.js v17.4.0 版本中,還不支持以 https://開頭的說明符。我們可以在自定義加載器中,利用 Node.js 提供的鉤子機(jī)制,讓 Node.js 可以使用import 導(dǎo)入以 https:// 協(xié)議開頭的 ES 模塊。

在分析如何自定義 https 資源加載器前,我們需要先介紹一下 import 說明符的概念。

import 說明符

import 語句的說明符是 from 關(guān)鍵字之后的字符串,例如 import { sep } from 'path' 中的 'path'。說明符也用于 export from 語句,并作為import() 表達(dá)式的參數(shù)。

責(zé)任編輯:武曉燕 來源: 全棧修仙之路
相關(guān)推薦

2023-05-14 23:38:43

Glarity用戶視頻

2020-02-18 20:28:23

AI人工智能

2020-01-20 14:40:39

工具代碼開發(fā)

2014-10-11 09:15:36

2022-11-30 10:59:20

2012-04-12 09:53:02

2009-04-22 15:16:30

2021-12-29 18:18:59

開源MedusaShopify

2017-08-31 10:32:35

交付技術(shù)

2021-01-29 09:07:39

數(shù)據(jù)保護(hù)信息安全數(shù)據(jù)隱私

2011-08-16 17:36:50

SolarisIllumos

2022-07-14 10:54:15

Python代碼Matplotlib

2012-06-25 10:20:22

敏捷開發(fā)

2014-12-01 12:57:46

亞馬遜天貓海淘

2018-09-30 08:00:15

區(qū)塊鏈碳排放氣候

2020-07-23 08:24:14

CSS偽類選擇器

2022-07-27 12:07:58

云計算公有云云支出

2009-08-17 08:54:56

2015-07-09 14:41:15

2012-02-13 09:42:41

備份服務(wù)器數(shù)據(jù)中心
點贊
收藏

51CTO技術(shù)棧公眾號

成人国产精品视频| 欧美成人一区二免费视频软件| 日本道免费精品一区二区三区| 日韩wuma| 91久久国产婷婷一区二区| 国产999精品| 色狠狠av一区二区三区| 国产一区欧美二区三区| 澳门黄色一级片| 爽爽窝窝午夜精品一区二区| 欧美性猛片aaaaaaa做受| 亚洲美女自拍偷拍| 污视频软件在线观看| 毛片不卡一区二区| 久久青草福利网站| 神马久久久久久久久久久| 一区二区三区在线免费看 | 午夜免费一区| 亚洲精品福利免费在线观看| 久久av电影| 久久精品免视看| 欧美在线视频播放| 多男操一女视频| 日韩欧美影院| 日韩欧美国产成人一区二区| 色七七在线观看| xxxx成人| 一区二区三区日韩欧美| 手机成人在线| 丝袜视频国产在线播放| 国产99一区视频免费| 国产精品亚洲自拍| 国产99免费视频| 午夜在线观看免费一区| 久久久这里只有精品视频| 亚洲ⅴ国产v天堂a无码二区| 国内精品国产成人国产三级粉色| 在线成人高清不卡| 天天操天天爽天天射| 极品白嫩少妇无套内谢| 波多视频一区| 午夜精品影院在线观看| 国产在线视频在线| 激情成人四房播| 中文字幕乱码一区二区免费| 美乳视频一区二区| 亚州男人的天堂| 成人高清视频免费观看| 成人情视频高清免费观看电影| 一区二区精品视频在线观看| 日本人妖一区二区| 国产成人精品午夜| 天堂网视频在线| 亚洲主播在线| 2021久久精品国产99国产精品| 久久久久香蕉视频| 国产精品分类| 欧美激情三级免费| 国产一级做a爱免费视频| 欧美在线亚洲| 欧美精品18videosex性欧美| 久久久久久福利| 99在线视频影院| 亚洲韩国一区二区三区| 草b视频在线观看| bl视频在线免费观看| 亚洲aaa精品| 日本少妇高潮喷水视频| 深夜成人在线| 一本大道久久a久久精品综合| aaa毛片在线观看| 欧美在线va视频| 欧美日韩三级一区| 免费黄频在线观看| 亚洲一二av| 日韩av在线资源| 色噜噜噜噜噜噜| 羞羞答答成人影院www| 久久99热精品| 国产精品21p| 美日韩一级片在线观看| 91九色偷拍| 西西人体44www大胆无码| 久久久久久97三级| 最新精品视频| heyzo在线播放| 欧美综合一区二区| 日本r级电影在线观看| 白嫩白嫩国产精品| 亚洲天堂男人天堂| 欧美性生给视频| 激情视频一区| 国产精品久久久久久影视| 国产精品人妻一区二区三区| 成人黄色小视频在线观看| 欧美日韩精品综合| 免费av网站在线看| 精品人伦一区二区三区蜜桃网站| 亚洲高清在线免费观看| www.神马久久| 色吧影院999| 中日韩黄色大片| 久久99日本精品| 国产另类自拍| 日本视频在线| 午夜久久久久久久久| 久久人人爽av| 特黄特色欧美大片| 欧美巨猛xxxx猛交黑人97人| 蜜臀99久久精品久久久久小说 | 奇米色欧美一区二区三区| 久久久极品av| 欧美a视频在线观看| 国产成人精品一区二区三区网站观看| 欧美精品二区三区四区免费看视频| 米奇精品一区二区三区| 精品国产成人av| 中文字幕久久久久久久| 欧美午夜精品一区二区三区电影| 亚州成人av在线| av免费观看在线| 国产精品视频免费看| 欧美日韩不卡在线视频| 精品午夜视频| 最好看的2019的中文字幕视频| 日本在线观看中文字幕| 国产乱码精品1区2区3区| 日本一区二区在线| 小视频免费在线观看| 精品乱人伦一区二区三区| 国产大屁股喷水视频在线观看| 好吊色在线视频| 午夜一区二区三区不卡视频| 高清视频一区| 伊人福利在线| 91精品国产欧美一区二区成人| 欧美黄色高清视频| 丝袜美腿高跟呻吟高潮一区| 精品国产乱码久久久久久88av | 亚洲av无码乱码国产麻豆| 日本一区二区三区高清不卡| 国产三区在线视频| 日韩丝袜视频| 欧美一区二区三区艳史| 性xxxx视频| 日韩欧美一区二区三区久久| 日本黄色动态图| 亚洲国产高清视频| 国产欧美丝袜| 爱啪啪综合导航| 亚洲黄色片网站| 国产欧美一区二区三区在线看蜜臂| 国产一区二区不卡老阿姨| 自拍另类欧美| 国产亚洲精aa在线看| 久久高清视频免费| av综合在线观看| 亚洲一线二线三线视频| 波多野结衣办公室双飞| 日韩视频二区| 日韩电影天堂视频一区二区| 国产综合色在线观看| 色阁综合伊人av| 国产又粗又猛又黄又爽| 亚洲免费观看高清完整版在线观看| 99久久99精品| 狠久久av成人天堂| 久久久99爱| 欧美xnxx| 久久天天躁狠狠躁老女人| www.色视频| 狠狠躁天天躁日日躁欧美| 欧美老熟妇乱大交xxxxx| 久久欧美肥婆一二区| 亚洲一二区在线| 亚洲3区在线| 538国产精品一区二区免费视频| 欧美孕妇性xxxⅹ精品hd| 欧美综合久久久| 中文字幕av久久爽av| a美女胸又www黄视频久久| 无码日韩人妻精品久久蜜桃| 99久久亚洲精品| 国产一区二区精品免费| 韩国成人在线| 欧美大片va欧美在线播放| 深夜福利在线视频| 欧美精品色综合| 欧美一区二区激情视频| 中文字幕av不卡| 日韩黄色一区二区| 日韩黄色一级片| av日韩在线看| 欧美精品久久久久久| 不卡一区二区三区视频| 欧洲精品一区二区三区| 久久久久久69| 成人在线免费公开观看视频| 日韩欧美国产1| 波多野结衣爱爱| 亚洲最新在线观看| 国产精品久久久久无码av色戒| 日本不卡一区二区三区| 无码日本精品xxxxxxxxx| 国产成人精品三级高清久久91| 亚洲精品免费在线视频| 成人做爰视频www网站小优视频| 美女av一区二区三区| 国产免费av高清在线| 亚洲成人精品在线| 亚洲天堂网视频| 一本大道久久a久久精二百| 久草成人在线视频| 国产精品美女一区二区三区 | 国产精品剧情在线亚洲| 熟女丰满老熟女熟妇| 国产999精品久久久久久绿帽| 91国内在线播放| 日韩影院在线观看| 激情五月宗合网| 午夜天堂精品久久久久| 一道精品一区二区三区| 国内亚洲精品| 你懂的网址一区二区三区| 久久久伦理片| 成人黄视频免费| 欧美日本三级| 成人网在线视频| 欧美日韩破处视频| 国产精品久久久久久久久免费| 九色porny视频在线观看| 欧美区在线播放| 中文字幕伦理免费在线视频 | 亚洲第一级黄色片| 国产福利视频导航| 3atv在线一区二区三区| 在线黄色av网站| 欧美唯美清纯偷拍| 亚洲 小说区 图片区| 在线精品观看国产| 无码人妻精品一区二区三区蜜桃91| 午夜亚洲国产au精品一区二区| 久久久久久久国产精品毛片| 玉足女爽爽91| 久久久一二三区| 亚洲成人777| 日韩成人一区二区三区| 亚洲成av人片| 国产情侣在线视频| 精品久久久久人成| 天天干天天干天天干天天| 岛国av在线不卡| 久久高清无码视频| 亚洲电影在线免费观看| 日韩欧美一级视频| 一本大道久久a久久综合| 国产又粗又猛又爽又| 91九色最新地址| 亚洲天堂男人网| 日韩午夜精品视频| 亚洲国产精品久久人人爱潘金莲 | 国产在线精品一区免费香蕉| 国产麻豆一区| 91九色露脸| 女仆av观看一区| 欧日韩一区二区三区| 日韩电影在线视频| 黄色网zhan| 99成人在线| 可以免费在线看黄的网站| 老司机免费视频一区二区| 国产精品嫩草影院8vv8| 国产成人在线视频网站| 中国av免费看| 日本一区二区三区在线观看| 欧美成人777| 五月天激情综合| 中文字幕一区二区三区四区免费看 | 国产精品理伦片| 老湿机69福利| 欧美日韩在线另类| 在线观看视频二区| 亚洲福利影片在线| 二区在线观看| 久久久久国色av免费观看性色| 欧美大胆成人| 亚洲直播在线一区| 欧美禁忌电影| 青春草在线视频免费观看| 99综合在线| 色天使在线观看| 99精品国产视频| 极品美妇后花庭翘臀娇吟小说| 午夜久久久久久电影| 一本色道久久综合熟妇| 亚洲成人久久网| 天堂中文а√在线| 欧美亚洲午夜视频在线观看| 欧洲午夜精品| 久久综合精品一区| 欧美体内she精视频在线观看| 狠狠热免费视频| 成人永久免费视频| 99自拍偷拍视频| 午夜久久久久久久久| 国产精品视频久久久久久| 精品一区精品二区| 永久免费网站在线| 国产美女精品视频| 亚洲69av| 欧美又粗又长又爽做受| 激情另类小说区图片区视频区| 一级性生活大片| 亚洲一区二区高清| 国产又大又长又粗| 中文字幕国产精品| 激情都市亚洲| 精品在线一区| 欧美久久久久| 手机在线观看日韩av| 国产精品欧美极品| 性色av免费观看| 亚洲级视频在线观看免费1级| 3d玉蒲团在线观看| 国产精品免费视频久久久| 男男gay无套免费视频欧美| 天堂…中文在线最新版在线| 国产精一区二区三区| 成人三级视频在线观看| 欧美色大人视频| h视频在线免费| 国产精品video| 亚洲小说图片视频| 国产午夜福利在线播放| 成人动漫av在线| 亚洲一区 视频| 精品播放一区二区| av福利导福航大全在线| 国产成人精品日本亚洲11| 国产一区亚洲| 亚洲AV成人精品| 亚洲一区二区视频在线| 亚洲第一页视频| 国语自产在线不卡| 欧美人成在线观看ccc36| 久草热视频在线观看| 久久综合色播五月| 无码一区二区三区| 国产亚洲精品久久久久久牛牛 | 国产午夜精品久久久久免费视| 国产精品男人爽免费视频1| 欧美天天综合| 日本高清久久久| 一区二区三区小说| 蜜臀av免费在线观看| 91av在线免费观看| 免费看成人吃奶视频在线| wwwwxxxx日韩| 亚洲精品视频一区| 内射无码专区久久亚洲| 97香蕉久久超级碰碰高清版| 亚洲最好看的视频| 亚洲一级免费观看| 亚洲免费观看高清| 狠狠躁夜夜躁av无码中文幕| 91av视频在线观看| 成人情趣视频网站| 久久aaaa片一区二区| 亚洲成人av资源| 户外极限露出调教在线视频| 国产精品视频免费在线观看| 雨宫琴音一区二区三区| 亚洲国产精品狼友在线观看| 欧美丝袜一区二区| 午夜视频在线| 国产视频精品网| 蜜桃视频一区二区三区在线观看 | 色三级在线观看| 99国产在线| 久久久久在线| 日本福利片在线观看| 亚洲精品www| 欧美一级做一级爱a做片性| 欧美中日韩在线| 国产日韩精品一区二区浪潮av| 精品人妻一区二区三区蜜桃| 69av在线播放| 国产高清一区| 国产制服丝袜在线| 777久久久精品| 午夜不卡影院| av一区二区三区免费观看| 91毛片在线观看| 超碰在线人人干| 国产精品av电影| 激情婷婷亚洲| 男女全黄做爰文章| 国产丝袜一区二区三区免费视频| 精品国产亚洲一区二区三区在线 | 欧美激情黑白配|