es6 import from xx , 是怎麼實現找到 node_modules目錄下的?

es6 impot Vue from vue 這樣寫 可以自動引用 node_modules 裡面的 ../node_modules/vue/dist/vue.js。那麼有沒有什麼辦法可以自己寫一種配置之類的,在不加入node_modules的情況下,實現不寫路徑。或者說,他是怎麼找到 node_modules目錄下的。


這個和 ES6 沒有關係,是模塊系統的約定以及實現。在 node 文檔裡面詳細描述了處理過程。

在 Node.js 模塊系統中,如果 require 的模塊不是核心模塊,而且沒有 ./ 之類的開頭,那就需要從當前 package 的 node_modules 裡面找,找不到就到當前 package 目錄上層 node_modules 裡面取... 一直找到全局 node_modules 目錄。

這樣找到的往往是文件夾,所以接下來就是處理一個文件目錄作為 Node 模塊的情況。如果文件目錄下有 package.json,就根據它的 main 欄位找到 js 文件。如果沒有 package.json,那就默認取文件夾下的 index.js。

由於 webpack browsersify 等模塊打包工具是兼容 node 的模塊系統的,自然也會進行同樣的處理流程。不同的是,它們支持更靈活的配置。比如在 webpack 裡面,可以通過 alias 和 external 欄位配置,實現對默認 import 邏輯的自定義。

webpack.config.js

alias: {
Icon: path.resolve(__dirname, src/components/Icon.jsx,
}

tets.js

import Icon from Icon // -&> /path/to/src/components/Icon.jsx

Facebook 有一套前端模塊系統叫做 Haste,現在 React 在用,所有模塊被引用只需要文件名,不用帶路徑。這樣解決了 import 路徑又臭又長的毛病,也避免重構目錄結構後需要大量修改相對路徑的問題。但是這樣做的前提是,一個項目下的所有源碼文件名稱都必須保證唯一。

在 webpack 中,要實現類似的特性是非常簡單的。你只需要在 webpack.config 裡面遍歷所有的源碼文件,生成一個「文件名: 路徑」的對象,然後做一下防重判斷,強制文件名必須唯一,再把這個對象塞給 resolve.alias 欄位,就可以了。

但是這種操作畢竟不是標準,會有一些缺點:

  1. 編輯器支持會有問題,不能正確識別這種引用方式,可能需要插件才能解決。
  2. Node 不支持。如果代碼需要同時被 Node 和前端代碼引用,就不行。

參考:

Node.js v8.4.0 Documentation

Resolve - Webpack

Codebase Overview - React

Support custom root directory alias for imports · Issue #14907 · Microsoft/vscode


相信你用的不是 nightly build,那麼 Node.js 在提問時還不支持 import,實際上是轉譯成 require() 了,require() 怎麼找,import 就怎麼找咯。

至於 Node.js 自己支持以後,規範有規定嘛:nodejs/node-eps


思路最高贊已經說了,具體實現可以自己看代碼啊:https://github.com/nodejs/node/blob/master/lib/module.js

Module._load = function(request, parent, isMain) {
// 1. Check Module._cache for the cached module.
// 2. Create a new Module instance if cache is empty.
// 3. Save it to the cache.
// 4. Call module.load() with your the given filename.
// This will call module.compile() after reading the file contents.
// 5. If there was an error loading/parsing the file,
// delete the bad module from the cache
// 6. return module.exports
};

參考:The Node.js Way - How `require()` Actually Works


這是 webpack 打包時採用 Node.js 的模塊查找規範進行查找的,和 ES6 無關


推薦閱讀:

Node.js伺服器端項目怎麼打包成單文件?
如何在Node.js或TypeScript中實現for..of形式的按行讀文件?
js中Async/Await 怎麼做錯誤處理更好?
GitHub上有哪些值得關注學習的NodeJS開源項目?

TAG:Nodejs | ECMAScript2015 |