package.json 中 你還不清楚的 browser,module,main 字段優先級

browser VS module VS main

前端開發中使用到 npm 包那可算是屢見不鮮,而使用到 npm 包總免不了接觸到 package.json 包配置文件。javascript

那麼這裏就有一個問題,當咱們在不一樣環境下 import 一個 npm 包時,到底加載的是 npm 包的哪一個文件?前端

老司機們很快地給出答案:main 字段中指定的文件java

然而咱們清楚 npm 包其實又分爲:node

  • 只容許在客戶端使用的,
  • 只容許造服務端使用的,
  • 瀏覽器/服務端均可以使用。

若是咱們須要開發一個 npm 包同時兼容支持 web端 和 server 端,須要在不一樣環境下加載npm包不一樣的入口文件,顯然一個 main 字段已經不可以知足咱們的需求,這就衍生出來了 modulebrowser 字段。webpack

本文就來講下 這幾個字段的使用場景,以及同時存在這幾個字段時,他們之間的優先級。git

文件優先級

在說 package.json 以前,先說下文件優先級github

因爲咱們使用的模塊規範有 ESM 和 commonJS 兩種,爲了能在 node 環境下原生執行 ESM 規範的腳本文件,.mjs 文件就應運而生。web

當存在 index.mjsindex.js 這種同名不一樣後綴的文件時,import './index' 或者 require('./index') 是會優先加載 index.mjs 文件的。面試

也就是說,優先級 mjs > jsnpm

browsermodulemain 字段

字段定義

  • main : 定義了 npm 包的入口文件,browser 環境和 node 環境都可使用
  • module : 定義 npm 包的 ESM 規範的入口文件,browser 環境和 node 環境都可使用
  • browser : 定義 npm 包在 browser 環境下的入口文件

使用場景與優先級

首先,咱們假定 npmtest 有如下目錄結構

----- lib
   |-- index.browser.js
   |-- index.browser.mjs
   |-- index.js
   |-- index.mjs
複製代碼

其中 *.js 文件是使用 commonJS 規範的語法(require('xxx')),*.mjs 是用 ESM 規範的語法(import 'xxx')

其 package.json 文件:

"main": "lib/index.js",  // main 
  "module": "lib/index.mjs", // module

  // browser 可定義成和 main/module 字段一一對應的映射對象,也能夠直接定義爲字符串
  "browser": {
    "./lib/index.js": "./lib/index.browser.js", // browser+cjs
    "./lib/index.mjs": "./lib/index.browser.mjs"  // browser+mjs
  },

  // "browser": "./lib/index.browser.js" // browser
複製代碼

根據上述配置,那麼其實咱們的 package.json 指定的入口能夠有

  • main
  • module
  • browser
  • browser+cjs
  • browser+mjs 這 5 種狀況。

下面說下具體使用場景。

webpack + web + ESM

這是咱們最多見的使用場景,經過 webpack 打包構建咱們的 web 應用,模塊語法使用 ESM

當咱們加載

import test from 'test'
複製代碼

實際上的加載優先級是 browser = browser+mjs > module > browser+cjs > main
也就是說 webpack 會根據這個順序去尋找字段指定的文件,直到找到爲止。

然而實際上的狀況可能比這個更加複雜,具體能夠參考流程圖

image

webpack + web + commonJS

const test = require('test')
複製代碼

事實上,構建 web 應用時,使用 ESM 或者 commonJS 模塊規範對於加載優先級並無任何影響

優先級依然是 browser = browser+mjs > module > browser+cjs > main

webpack + node + ESM/commonJS

咱們清楚,使用 webpack 構建項目的時候,有一個 target 選項,默認爲 web,即進行 web 應用構建。

當咱們須要進行一些 同構項目,或者其餘 node 項目的構建的時候,咱們須要將 webpack.config.jstarget 選項設置爲 node 進行構建。

import test from 'test'
// 或者 const test = require('test')
複製代碼

優先級是: module > main

node + commonJS

經過 node test.js 直接執行腳本

const test = require('test')
複製代碼

只有 main 字段有效。

node + ESM

經過 --experimental-modules 可讓 node 執行 ESM 規範的腳本(必須是 mjs 文件後綴)
`node --experimental-modules test.mjs

import test from 'test'
複製代碼

只有 main 字段有效。

總結

  • 若是 npm 包導出的是 ESM 規範的包,使用 module
  • 若是 npm 包只在 web 端使用,而且嚴禁在 server 端使用,使用 browser。
  • 若是 npm 包只在 server 端使用,使用 main
  • 若是 npm 包在 web 端和 server 端都容許使用,使用 browser 和 main
  • 其餘更加複雜的狀況,如npm 包須要提供 commonJS 與 ESM 等多個規範的多個代碼文件,請參考上述使用場景或流程圖



本文首發於 github 博客
如文章對你有幫助,你的 star 是對我最大的支持
其餘文章:


插播廣告:
深圳 Shopee 長期內推
崗位:前端,後端(要轉go),產品,UI,測試,安卓,IOS,運維 全都要。
薪酬福利:20K-50K😳,7點下班😏,免費水果😍,免費晚餐😊,15天年假👏,14天帶薪病假。 點擊查看詳情 簡歷發郵箱:chenweiyu6909@gmail.com 或者加我微信:cwy13920,實時反饋面試進度哦。

相關文章
相關標籤/搜索