日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務時間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
如何正確地配置入口文件?

寫在前面

在node中支持兩種模塊方案——CommonJS(cjs) 和 ECMAScript modules (esm)。

成都創(chuàng)新互聯(lián)公司是專業(yè)的磁縣網(wǎng)站建設(shè)公司,磁縣接單;提供成都做網(wǎng)站、成都網(wǎng)站設(shè)計、成都外貿(mào)網(wǎng)站建設(shè),網(wǎng)頁設(shè)計,網(wǎng)站設(shè)計,建網(wǎng)站,PHP網(wǎng)站建設(shè)等專業(yè)做網(wǎng)站服務;采用PHP框架,可快速的進行磁縣網(wǎng)站開發(fā)網(wǎng)頁制作和功能擴展;專業(yè)做搜索引擎喜愛的網(wǎng)站,專業(yè)的做網(wǎng)站團隊,希望更多企業(yè)前來合作!

隨著ESModule的廣泛使用,社區(qū)生態(tài)也在逐漸轉(zhuǎn)向ESModule,ESModule相比于require的運行時執(zhí)行,可以用來做一些靜態(tài)代碼分析如tree shaking等來減小代碼體積,但是由于CommonJS已有龐大的用戶基礎(chǔ),對于第三方庫作者來說,不能完全一刀切只用ESModule,還要兼容CommonJS場景的使用,所以最合理的方式就是“魚和熊掌兼得”,即使用ESModule編寫庫代碼,然后通過TypeScript、Babel等工具輔助生成對應的CommonJS格式的代碼,然后根據(jù)開發(fā)者的引用方式來動態(tài)替換為指定格式的代碼。

有了兩種版本的代碼,第三方庫作者就需要編寫相應的入口文件,來達到“動態(tài)”引入的目的(即import引用的時候指向ESModule的代碼,require引入則指向CommonJS的代碼),同時也方便于打包工具對于無用代碼的剔除,減少代碼體積,本篇文章主要聚焦于如何正確地配置入口文件。

注:本篇文章以node規(guī)范為準,對于打包工具額外支持的配置方式會進行額外標注

本文的涉及的示例代碼可以通過 https://github.com/HomyeeKing/test-entry 進行查看、測試

main

package.json的 main字段是最常見的指定入口文件的形式。

{
"name": "@homy/test-entry",
"version": "1.0.0",
"description": "",
"main": "index.js"
}

當開發(fā)者引入@homy/test-entry這個包的時候,可以確定@homy/test-entry 這個npm包的入口文件指向的是 index.js。

const pkg = require('@homy/test-entry')

但是index.js究竟是cjs or esm?

一種方式是我們可以通過后綴名來顯示地標注出當前文件是cjs還是esm格式的:

  • cjs ---> .cjs
  • esm ---> .mjs

那么不同模塊格式的文件如何相互引用呢?解釋規(guī)則大致如下

  • import了CJS格式的文件,module.exports會等同于export default, 具名導入會根據(jù)靜態(tài)分析來兼容,但是一般推薦在ESM中使用defaultExport格式來引入CJS文件
  • 在CJS中,如果想要引入ESM文件,因為ESM模塊異步執(zhí)行的機制,必須使用Dynamic Import即import()來引用
// index.cjs
const pkg = require('./index.mjs') // Error
const pkg = await import('./index.mjs') //

// index.mjs
import { someVar } from './index.cjs' // ? it dependens 推薦下邊方式引入
import pkg from './index.cjs' //

另一種方式是通過package.json的 type字段來標識

type

package.json 里也提供了一個type字段 用于標注用什么格式來執(zhí)行.js文件,

{
"name": "@homy/test-entry",
"version": "1.0.0",
"description": "",
"type": "commonjs", // or "module", 默認是 commonjs
"main": "index.js"
}

如果手動設(shè)置type: module, 則將index.js當做esmodule處理,否則視為CommonJS

type: module ,只有Node.js >= 14 且使用import才能使用,不支持require引入

注:關(guān)于.js的詳細解析策略推薦閱讀 https://nodejs.org/api/modules.html#enabling

通過type和main字段,我們可以指定入口文件以及入口文件是什么類型,但是指定的只是一個入口文件,仍然不能夠滿足我們“動態(tài)”引入的需求,所以node又引入exports這個新的字段作為main更強大的替代品。

exports

相比較于main字段,exports可以指定多個入口文件,且優(yōu)先級高于main

{
"name": "@homy/test-entry",
"main": "index.js",
"exports":{
"import":"./index.mjs",
"require":"./index.cjs",
"default": "./index.mjs" // 兜底使用
},
}

而且還有效限制了入口文件的范圍,即如果你引入指定入口文件范圍之外的文件,則會報錯

const pkg = require('@homy/test-entry/test.js'); 
// 報錯!Package subpath './test.js' is not defined by "exports"

如果想指定submodule, 我們可以這樣編寫

"exports": {
"." : "./index.mjs",
"./mobile": "./mobile.mjs",
"./pc": "./pc.mjs"
},

// or 更詳細的配置

"exports": {
".":{
"import":"./index.mjs",
"require":"./index.cjs",
"default": "./index.mjs"
},
"./mobile": {
"import":"./mobile.mjs",
"require":"./mobile.cjs",
"default": "./mobile.mjs"
}
},

然后通過如下方式可以訪問到子模塊文件

import pkg from 'pkg/mobile'

另外還有一個imports 字段,主要用于控制import的解析路徑,類似于Import Maps, 不過在node中指定的入口需要以#開頭,感興趣的可以閱讀subpath-imports

對于前端日常開發(fā)來說,我們的運行環(huán)境主要還是瀏覽器和各種webview,我們會使用各種打包工具來壓縮、轉(zhuǎn)譯我們的代碼,除了上面提到的main exports字段,被主流打包工具廣泛支持的還有一個module字段

module

大部分時候 我們也能在第三方庫中看到module這個字段,用來指定esm的入口,但是這個提案沒有被node采納(使用exports)但是大多數(shù)打包工具比如webpack、rollup以及esbuild等支持了這一特性,方便進行tree shaking等優(yōu)化策略

另外,TypeScript已經(jīng)成為前端的主流開發(fā)方式,同時TypeScript也有自己的一套入口解析方式,只不過解析的是類型的入口文件,有效輔助開發(fā)者進行類型檢查和代碼提示,來提高我們編碼的效率和準確性,下面我們繼續(xù)了解下TypeScript是怎么解析類型文件的。

Type Script的凱瑞小入口文件

TypeScript有著對Node的原生支持,所以會先檢查main字段,然后找對應文件是否存在類型聲明文件,比如main指向的是lib/index.js, TypeScript就會查找有沒有l(wèi)ib/index.d.ts文件。

另外一種方式,開發(fā)者可以在package.json中通過types字段來指定類型文件,exports中同理。

{
"name": "my-package",
"type": "module",
"exports": {
".": {
// Entry-point for TypeScript resolution - must occur first!
"types": "./types/index.d.ts",
// Entry-point for `import "my-package"` in ESM
"import": "./esm/index.js",
// Entry-point for `require("my-package") in CJS
"require": "./commonjs/index.cjs",
},
},
// CJS fall-back for older versions of Node.js
"main": "./commonjs/index.cjs",
// Fall-back for older versions of TypeScript
"types": "./types/index.d.ts"
}

?  TypeScript模塊解析策略

tsconfig.json包含一個moduleResolution字段,支持classic(默認)和node兩種解析策略,主要針對相對路徑引入和非相對路徑引入兩種方式,我們可以通過示例來理解下

?  classic

查找以.ts 或.d.ts結(jié)尾的文件

  • relative import
//  /root/src/folder/A.ts
import { b } from "./moduleB"


// process:
/root/src/folder/moduleB.ts
/root/src/folder/moduleB.d.ts

相對路徑會找當前目錄下的.ts 或.d.ts的文件

  • no-relative import
//  /root/src/folder/A.ts
import { b } from "moduleB"


// process:
/root/src/folder/moduleB.ts
/root/src/folder/moduleB.d.ts
/root/src/moduleB.ts
/root/src/moduleB.d.ts
/root/moduleB.ts
/root/moduleB.d.ts
/moduleB.ts

則會向上查找,直到找到moduleB 相關(guān)的.ts或.d.ts文件

?  node

以類似于node的解析策略來查找,但是相應的查找的范圍是以.ts .tsx .d.ts為后綴的文件,而且會讀取package.json中對應的types(或typings)字段

  • relative
/root/src/moduleA
const pkg = require('./moduleB')

// process:
/root/src/moduleB.js
/root/src/package.json (查找/root/src下有無package.json 如果指定了main字段 則指向main字段對應的文件)
/root/src/moduleB/index.js

在node環(huán)境下,會依次解析.js 當前package.json中main字段指向的文件以及是否存在對應的index.js文件。

TypeScript解析的時候則是把后綴名替換成ts專屬的后綴.ts .tsx .d.ts,而且ts這時候會讀取types字段 而非main

/root/src/moduleB.ts
/root/src/moduleB.tsx
/root/src/moduleB.d.ts
/root/src/moduleB/package.json (if it specifies a types property)
/root/src/moduleB/index.ts
/root/src/moduleB/index.tsx
/root/src/moduleB/index.d.ts
  • no-relative

no-relative就直接查看指定node_modules下有沒有對應文件

/root/src/moduleA
const pkg = require('moduleB')

// process:
/root/src/node_modules/moduleB.js
/root/src/node_modules/package.json
/root/src/node_modules/moduleB/index.js

/root/node_modules/moduleB.js
/root/node_modules/moduleB/package.json (if it specifies a "main" property)
/root/node_modules/moduleB/index.js

/node_modules/moduleB.js
/node_modules/moduleB/package.json (if it specifies a "main" property)
/node_modules/moduleB/index.js

類似的 TypeScript也會替換對應后綴名,而且多了@types下類型的查找

/root/src/node_modules/moduleB.ts
/root/src/node_modules/moduleB.tsx
/root/src/node_modules/moduleB.d.ts
/root/src/node_modules/moduleB/package.json (if it specifies a types property)
/root/src/node_modules/@types/moduleB.d.ts <----- check out @types
/root/src/node_modules/moduleB/index.ts
/root/src/node_modules/moduleB/index.tsx
/root/src/node_modules/moduleB/index.d.ts
....

另外TypeScript支持版本選擇來映射不同的文件,感興趣的可以閱讀version-selection-with-typesversions(地址:https://www.typescriptlang.org/docs/handbook/declaration-files/publishing.html#version-selection-with-typesversions)

總結(jié)

  1. node中可以通過main 和 type: module | commonjs 來指定入口文件及其模塊類型, exports 則是更強大的替代品,擁有更靈活的配置方式
  2. 主流打包工具如webpack rollup esbuild 則在此基礎(chǔ)上增加了對top-level module的支持
  3. TypeScript 則會先查看package.json中有沒有types字段,否則查看main字段指定的文件有沒有對應的類型聲明文件

網(wǎng)站題目:如何正確地配置入口文件?
網(wǎng)站地址:http://m.5511xx.com/article/dhejods.html