摘要:目前主流的模塊規(guī)范模塊通用模塊如果你在文件頭部看到這樣的代碼,那么這個文件使用的就是規(guī)范實際上就是全局變量這三種風(fēng)格的結(jié)合這段代碼就是對當前運行環(huán)境的判斷,如果是環(huán)境就是使用規(guī)范,如果不是就判斷是否為環(huán)境,最后導(dǎo)出全局變量有了后我們的代碼和
目前主流的模塊規(guī)范
UMD
CommonJs
es6 module
umd 模塊(通用模塊)(function (global, factory) { typeof exports === "object" && typeof module !== "undefined" ? module.exports = factory() : typeof define === "function" && define.amd ? define(factory) : (global.libName = factory()); }(this, (function () { "use strict";})));
如果你在js文件頭部看到這樣的代碼,那么這個文件使用的就是 UMD 規(guī)范
實際上就是 amd + commonjs + 全局變量 這三種風(fēng)格的結(jié)合
這段代碼就是對當前運行環(huán)境的判斷,如果是 Node 環(huán)境 就是使用 CommonJs 規(guī)范, 如果不是就判斷是否為 AMD 環(huán)境, 最后導(dǎo)出全局變量
有了 UMD 后我們的代碼和同時運行在 Node 和 瀏覽器上
所以現(xiàn)在前端大多數(shù)的庫最后打包都使用的是 UMD 規(guī)范
Nodejs 環(huán)境所使用的模塊系統(tǒng)就是基于CommonJs規(guī)范實現(xiàn)的,我們現(xiàn)在所說的CommonJs規(guī)范也大多是指Node的模塊系統(tǒng)
模塊導(dǎo)出關(guān)鍵字:module.exports exports
// foo.js //一個一個 導(dǎo)出 module.exports.age = 1 module.exports.foo = function(){} exports.a = "hello" //整體導(dǎo)出 module.exports = { age: 1, a: "hello", foo:function(){} } //整體導(dǎo)出不能用`exports` 用exports不能在導(dǎo)入的時候使用 exports = { age: 1, a: "hello", foo:function(){} }
這里需要注意 exports 不能被賦值,可以理解為在模塊開始前exports = module.exports, 因為賦值之后exports失去了 對module.exports的引用,成為了一個模塊內(nèi)的局部變量
模塊導(dǎo)入關(guān)鍵字:require
const foo = require("./foo.js") console.log(foo.age) //1模塊導(dǎo)入規(guī)則:
假設(shè)以下目錄為 src/app/index.js 的文件 調(diào)用 require()
在沒有指定后綴名的情況下
先去尋找同級目錄同級目錄:src/app/
src/app/moduleA 無后綴名文件 按照javascript解析
src/app/moduleA.js js文件 按照javascript解析
src/app/moduleA.json json文件 按照json解析
src/app/moduleA.node node文件 按照加載的編譯插件模塊dlopen
同級目錄沒有 moduleA 文件會去找同級的 moduleA目錄:src/app/moduleA
src/app/moduleA/package.json 判斷該目錄是否有package.json文件, 如果有 找到main字段定義的文件返回, 如果 main 字段指向文件不存在 或 main字段不存在 或 package.json文件不存在向下執(zhí)行
src/app/moduleA/index.js
src/app/moduleA/index.json
src/app/moduleA/index.node
結(jié)束
直接在/module/moduleA目錄中尋找 規(guī)則同上
沒有路徑開頭則視為導(dǎo)入一個包
會先判斷moduleA是否是一個核心模塊 如path,http,優(yōu)先導(dǎo)入核心模塊
不是核心模塊 會從當前文件的同級目錄的node_modules尋找
/src/app/node_modules/ 尋找規(guī)則同上 以導(dǎo)入react為例 先 node_modules 下 react 文件 -> react.js -> react.json -> react.node ->react目錄 -> react package.json main -> index.js -> index.json -> index.node 如果沒找到 繼續(xù)向父目錄的node_modules中找
/src/node_modules/
/node_modules/
直到最后找不到 結(jié)束
require wrapperNode的模塊 實際上可以理解為代碼被包裹在一個函數(shù)包裝器內(nèi)
一個簡單的require demo:
function wrapper (script) { return "(function (exports, require, module, __filename, __dirname) {" + script + " })" } function require(id) { var cachedModule = Module._cache[id]; if(cachedModule){ return cachedModule.exports; } const module = { exports: {} } // 這里先將引用加入緩存 后面循環(huán)引用會說到 Module._cache[id] = module //當然不是eval這么簡單 eval(wrapper("module.exports = "123""))(module.exports, require, module, "filename", "dirname") return module.exports }
也可以查看:node module 源碼
從以上代碼我們可以知道:
模塊只執(zhí)行一次 之后調(diào)用獲取的 module.exports 都是緩存哪怕這個 js 還沒執(zhí)行完畢(因為先加入緩存后執(zhí)行模塊)
模塊導(dǎo)出就是return這個變量的其實跟a = b賦值一樣, 基本類型導(dǎo)出的是值, 引用類型導(dǎo)出的是引用地址
exports 和 module.exports 持有相同引用,因為最后導(dǎo)出的是 module.exports, 所以對exports進行賦值會導(dǎo)致exports操作的不再是module.exports的引用
循環(huán)引用// a.js module.exports.a = 1 var b = require("./b") console.log(b) module.exports.a = 2 // b.js module.exports.b = 11 var a = require("./a") console.log(a) module.exports.b = 22 //main.js var a = require("./a") console.log(a)
運行此段代碼結(jié)合上面的require demo,分析每一步過程:
執(zhí)行 node main.js -> 第一行 require(a.js),(node 執(zhí)行也可以理解為調(diào)用了require方法,我們省略require(main.js)內(nèi)容)
進入 require(a)方法: 判斷緩存(無) -> 初始化一個 module -> 將 module 加入緩存 -> 執(zhí)行模塊 a.js 內(nèi)容,(需要注意 是先加入緩存, 后執(zhí)行模塊內(nèi)容)
a.js: 第一行導(dǎo)出 a = 1 -> 第二行 require(b.js)(a 只執(zhí)行了第一行)
進入 require(b) 內(nèi) 同 1 -> 執(zhí)行模塊 b.js 內(nèi)容
b.js: 第一行 b = 11 -> 第二行 require(a.js)
require(a) 此時 a.js 是第二次調(diào)用 require -> 判斷緩存(有)-> cachedModule.exports -> 回到 b.js(因為js對象引用問題 此時的 cachedModule.exports = { a: 1 })
b.js:第三行 輸出 { a: 1 } -> 第四行 修改 b = 22 -> 執(zhí)行完畢回到 a.js
a.js:第二行 require 完畢 獲取到 b -> 第三行 輸出 { b: 22 } -> 第四行 導(dǎo)出 a = 2 -> 執(zhí)行完畢回到 main.js
main.js:獲取 a -> 第二行 輸出 { a: 2 } -> 執(zhí)行完畢
以上就是node的module模塊解析和運行的大致規(guī)則
es6 moduleES6 之前 javascript 一直沒有屬于自己的模塊規(guī)范,所以社區(qū)制定了 CommonJs規(guī)范, Node 從 Commonjs 規(guī)范中借鑒了思想于是有了 Node 的 module,而 AMD 異步模塊 也同樣脫胎于 Commonjs 規(guī)范,之后有了運行在瀏覽器上的 require.js
es6 module 基本語法:
exportexport * from "module"; //重定向?qū)С?不包括 module內(nèi)的default export { name1, name2, ..., nameN } from "module"; // 重定向命名導(dǎo)出 export { import1 as name1, import2 as name2, ..., nameN } from "module"; // 重定向重命名導(dǎo)出 export { name1, name2, …, nameN }; // 與之前聲明的變量名綁定 命名導(dǎo)出 export { variable1 as name1, variable2 as name2, …, nameN }; // 重命名導(dǎo)出 export let name1 = "name1"; // 聲明命名導(dǎo)出 或者 var, const,function, function*, class export default expression; // 默認導(dǎo)出 export default function () { ... } // 或者 function*, class export default function name1() { ... } // 或者 function*, class export { name1 as default, ... }; // 重命名為默認導(dǎo)出
export 規(guī)則
export * from "" 或者 export {} from "",重定向?qū)С觯囟ㄏ虻拿⒉荒茉诒灸K使用,只是搭建一個橋梁,例如:這個a并不能在本模塊內(nèi)使用
export {}, 與變量名綁定,命名導(dǎo)出
export Declaration,聲明的同時,命名導(dǎo)出, Declaration就是: var, let, const, function, function*, class 這一類的聲明語句
export default AssignmentExpression,默認導(dǎo)出, AssignmentExpression的 范圍很廣,可以大致理解 為除了聲明Declaration(其實兩者是有交叉的),a=2,i++,i/4,a===b,obj[name],name in obj,func(),new P(),[1,2,3],function(){}等等很多
import// 命名導(dǎo)出 module.js let a = 1,b = 2 export { a, b } export let c = 3 // 命名導(dǎo)入 main.js import { a, b, c } from "module"; // a: 1 b: 2 c: 3 import { a as newA, b, c as newC } from "module"; // newA: 1 b: 2 newC: 3 // 默認導(dǎo)出 module.js export default 1 // 默認導(dǎo)入 main.js import defaultExport from "module"; // defaultExport: 1 // 混合導(dǎo)出 module.js let a = 1 export { a } const b = 2 export { b } export let c = 3 export default [1, 2, 3] // 混合導(dǎo)入 main.js import defaultExport, { a, b, c as newC} from "module"; //defaultExport: [1, 2, 3] a: 1 b: 2 newC: 3 import defaultExport, * as name from "module"; //defaultExport: [1, 2, 3] name: { a: 1, b: 2, c: 3 } import * as name from "module"; // name: { a: 1, b: 2, c: 3, default: [1, 2, 3] } // module.js Array.prototype.remove = function(){} //副作用 只運行一個模塊 import "module"; // 執(zhí)行module 不導(dǎo)出值 多次調(diào)用module.js只運行一次 //動態(tài)導(dǎo)入(異步導(dǎo)入) var promise = import("module");import 規(guī)則
import { } from "module", 導(dǎo)入module.js的命名導(dǎo)出
import defaultExport from "module", 導(dǎo)入module.js的默認導(dǎo)出
import * as name from "module", 將module.js的的所有導(dǎo)出合并為name的對象,key為導(dǎo)出的命名,默認導(dǎo)出的key為default
import "module",副作用,只是運行module,不為了導(dǎo)出內(nèi)容例如 polyfill,多次調(diào)用次語句只能執(zhí)行一次
import("module"),動態(tài)導(dǎo)入返回一個 Promise,TC39的stage-3階段被提出 tc39 import
ES6 module 特點 ES6 module的語法是靜態(tài)的import 會自動提升到代碼的頂層
export 和 import 只能出現(xiàn)在代碼的頂層,下面這段語法是錯誤的
//if for while 等都無法使用 { export let a = 1 import defaultExport from "module" } true || export let a = 1
import 的導(dǎo)入名不能為字符串或在判斷語句,下面代碼是錯誤的
import "defaultExport" from "module" let name = "Export" import "default" + name from "module"
靜態(tài)的語法意味著可以在編譯時確定導(dǎo)入和導(dǎo)出,更加快速的查找依賴,可以使用lint工具對模塊依賴進行檢查,可以對導(dǎo)入導(dǎo)出加上類型信息進行靜態(tài)的類型檢查
ES6 module的導(dǎo)出是綁定的使用 import 被導(dǎo)入的模塊運行在嚴格模式下
使用 import 被導(dǎo)入的變量是只讀的,可以理解默認為 const 裝飾,無法被賦值
使用 import 被導(dǎo)入的變量是與原變量綁定/引用的,可以理解為 import 導(dǎo)入的變量無論是否為基本類型都是引用傳遞
// js中 基礎(chǔ)類型是值傳遞 let a = 1 let b = a b = 2 console.log(a,b) //1 2 // js中 引用類型是引用傳遞 let obj = {name:"obj"} let obj2 = obj obj2.name = "obj2" console.log(obj.name, obj2.name) // obj2 obj2 // es6 module 中基本類型也按引用傳遞 // foo.js export let a = 1 export function count(){ a++ } // main.js import { a, count } from "./foo" console.log(a) //1 count() console.log(a) //2 // export default 是無法 a 的動態(tài)綁定 這一點跟 CommonJs 有點相似 都是值的拷貝 let a = 1; export default a // 可以用另一種方式實現(xiàn) default 的動態(tài)綁定 let a = 1; export { a as default } export function count(){ a++ } // 就跟上面 main.js 一樣
上面這段代碼就是 CommonJs 導(dǎo)出變量 和 ES6 導(dǎo)出變量的區(qū)別
es module 循環(huán)引用// bar.js import { foo } from "./foo" console.log(foo); export let bar = "bar" // foo.js import { bar } from "./bar" console.log(bar); export let foo = "foo" // main.js import { bar } from "./bar" console.log(bar)
執(zhí)行 main.js -> 導(dǎo)入 bar.js
bar.js -> 導(dǎo)入 foo.js
foo.js -> 導(dǎo)入 bar.js -> bar.js 已經(jīng)執(zhí)行過直接返回 -> 輸出 bar -> bar is not defined, bar 未定義報錯
我們可以使用function的方式解決:
// bar.js import { foo } from "./foo" console.log(foo()); export function bar(){ return "bar" } // foo.js import { bar } from "./bar" console.log(bar()); export function foo(){ return "foo" } // main.js import { bar } from "./bar" console.log(bar)
因為函數(shù)聲明會提示到文件頂部,所以就可以直接在 foo.js 調(diào)用還沒執(zhí)行完畢的bar.js的 bar 方法,不要在函數(shù)內(nèi)使用外部變量,因為變量還未聲明(let,const)和賦值,var
CommonJs 和 ES6 Module 的區(qū)別其實上面我們已經(jīng)說到了一些區(qū)別
CommonJs導(dǎo)出的是變量的一份拷貝,ES6 Module導(dǎo)出的是變量的綁定(export default 是特殊的)
CommonJs是單個值導(dǎo)出,ES6 Module可以導(dǎo)出多個
CommonJs是動態(tài)語法可以寫在判斷里,ES6 Module靜態(tài)語法只能寫在頂層
CommonJs的 this 是當前模塊,ES6 Module的 this 是 undefined
易混淆點 模塊語法與解構(gòu)module語法與解構(gòu)語法很容易混淆,例如:
import { a } from "module" const { a } = require("module")
盡管看上去很像,但是不是同一個東西,這是兩種完全不一樣的語法與作用,ps:兩個人撞衫了,穿一樣的衣服你不能說這倆人就是同一個人
module 的語法: 上面有寫 import/export { a } / { a, b } / { a as c} FromClause
解構(gòu) 的語法:
let { a } = { a: 1 } let { a = 2 } = { } let { a: b } = { a: 1 } let { a: b = 2, ...res } = { name:"a" } let { a: b, obj: { name } } = { a: 1, obj: { name: "1" } } function foo({a: []}) {}
他們是差別非常大的兩個東西,一個是模塊導(dǎo)入導(dǎo)出,一個是獲取對象的語法糖
導(dǎo)出語法與對象屬性簡寫同樣下面這段代碼也容易混淆
let a = 1 export { a } // 導(dǎo)出語法 export default { a } // 屬性簡寫 導(dǎo)出 { a: 1 } 對象 module.exports = { a } // 屬性簡寫 導(dǎo)出 { a: 1 } 對象
export default 和 module.exports 是相似的
ES6 module 支持 CommonJs 情況先簡單說一下各個環(huán)境的 ES6 module 支持 CommonJs 情況,后面多帶帶說如何在不同環(huán)境中使用
因為 module.exports 很像 export default 所以 ES6模塊 可以很方便兼容 CommonJs
在ES6 module中使用CommonJs規(guī)范,根據(jù)各個環(huán)境,打包工具不同也是不一樣的
我們現(xiàn)在大多使用的是 webpack 進行項目構(gòu)建打包,因為現(xiàn)在前端開發(fā)環(huán)境都是在 Node 環(huán)境原因,而 npm 的包都是 CommonJs 規(guī)范的,所以 webpack 對ES6模塊進行擴展 支持 CommonJs,并支持node的導(dǎo)入npm包的規(guī)范
如果你使用 rollup,想在ES Module中支持Commonjs規(guī)范就需要下載rollup-plugin-commonjs插件,想要導(dǎo)入node_modules下的包也需要rollup-plugin-node-resolve插件
如果你使用 node,可以在 .mjs 文件使用 ES6,也支持 CommonJs 查看 nodejs es-modules.md
在瀏覽器環(huán)境 不支持CommonJs
node 與 打包工具webpack,rollup的導(dǎo)入 CommonJs 差異
// module.js module.export.a = 1 // index.js webpack rollup import * as a from "./module" console.log(a) // { a: 1, default: { a:1 } } // index.mjs node import * as a from "./module" console.log(a) // { default: { a:1 } }
node 只是把 module.exports 整體當做 export default
打包工具除了把 module.export 整體當做 export default,還把 module.export 的每一項 又當做 export 輸出,這樣做是為了更加簡潔
import defaultExport from "./foo", defaultExport.foo()
import { foo } from "./foo", foo()
可以在 es6module example 倉庫中獲取代碼在本地進行測試驗證
瀏覽器中使用你需要起一個Web服務(wù)器來訪問,雙擊本地運行 index.html 并不會執(zhí)行 type=module 標簽
我們可以對 script 標簽的 type 屬性加上 module
先定義兩個模塊
// index.js import module from "./module.js" console.log(module) // 123 // module.js export default 123
在html中內(nèi)聯(lián)調(diào)用
在html中通過 script 的 src 引用
// 控制臺 123瀏覽器導(dǎo)入路徑規(guī)則
https://example.com/apples.mjs
http://example.com/apples.js
//example.com/bananas
./strawberries.mjs.cgi
../lychees
/limes.jsx
data:text/javascript,export default "grapes";
blob:https://whatwg.org/d0360e2f-caee-469f-9a2f-87d5b0456f6f
補充:
不加 后綴名 找不到具體的文件
后端可以修改接口/getjs?name=module這一類的,不過后端要返回 Content-Type: application/javascript 確保返回的是js,因為瀏覽器是根據(jù) MIME type 識別的
因為 ES6 Module 在瀏覽器中兼容并不是很好兼容性表,這里就不介紹瀏覽器支持情況了,我們一般不會直接在瀏覽器中使用
Nodejs中使用nodejs es-modules.md
在 Node v8.5.0 以上支持 ES Module,需要 .mjs擴展名
NOTE: DRAFT status does not mean ESM will be implemented in Node core. Instead that this is the standard, should Node core decide to implement ESM. At which time this draft would be moved to ACCEPTED.
(上面鏈接可以知道 ES Module的狀態(tài)是 DRAFT, 屬于起草階段)
// module.mjs export default 123 // index.mjs import module from "./module.mjs" console.log(module) // 123
我們需要執(zhí)行 node --experimental-modules index.mjs 來啟動
會提示一個 ExperimentalWarning: The ESM module loader is experimental.該功能是實驗性的(此提示不影響執(zhí)行)
ES Module 中導(dǎo)入 CommonJs
// module.js module.exports.a = 123 // module.exports 就相當于 export default // index.mjs import module from "./module.js" console.log(module) // { a: 123 } import * as module from "./module.js" console.log(module) // { get default: { a: 123 } } import { default as module } from "./module.js"; console.log(module) // { a: 123 } import module from "module"; // 導(dǎo)入npm包 導(dǎo)入規(guī)則與 require 差不多
導(dǎo)入路徑規(guī)則與require差不多
這里要注意 module 擴展名為 .js,.mjs專屬于 es module,import form導(dǎo)入的文件后綴名只能是.mjs,在 .mjs中 module未定義, 所以調(diào)用 module.exports,exports 會報錯
node中 CommonJs 導(dǎo)入 es module 只能使用 import() 動態(tài)導(dǎo)入/異步導(dǎo)入
// es.mjs let foo = {name: "foo"}; export default foo; export let a = 1 // cjs import("./es").then((res)=>{ console.log(res) // { get default: {name: "foo"}, a: 1 } });webpack中使用
從 webpack2 就默認支持 es module 了,并默認支持 CommonJs,支持導(dǎo)入 npm包, 這里 import 語法上面寫太多 就不再寫了
rollup中使用rollup 專注于 es module,可以將 es module 打包為主流的模塊規(guī)范,注意這里與 webpack 的區(qū)別,我們可以在 webpack 的 js 中使用 Commonjs 語法, 但是 rollup 不支持,rollup需要 plugin 支持,包括加載 node_modules 下的包 form "react" 也需要 plugin 支持
可以看到 es module 在瀏覽器與node中兼容性差與實驗功能的
我們大多時候在 打包工具 中使用
在最后我們說一下經(jīng)常跟 es module 一起出現(xiàn)的一個名詞 Tree-shaking
Tree-shaking 我們先直譯一下 樹木搖晃 就是 搖晃樹木把上面枯死的樹葉晃下來,在代碼中就是把沒有用到的代碼刪除
Tree-shaking 最早由 rollup 提出,之后 webpack 2 也開始支持
這都是基于 es module 模塊特性的靜態(tài)分析
下面代碼使用 rollup 進行打包:
// module.js export let foo = "foo" export let bar = "bar" // index.js import { foo } from "./module" console.log(foo) // foo
在線運行 我們可以修改例子與導(dǎo)出多種規(guī)范
打包結(jié)果:
let foo = "foo"; console.log(foo); // foo
可以看到 rollup 打包結(jié)果非常的簡潔,并去掉了沒有用到的 bar
是否支持對導(dǎo)入 CommonJs 的規(guī)范進行 Tree-shaking:
// index.js import { a } from "./module" console.log(a) // 1 // module.js module.exports.a = 1 module.exports.b = 2
打包為 es module
var a_1 = 2; console.log(a_1);
可以看到去掉了未使用的 b
webpack我們下面看看 webpack 的支持情況
// src/module.js export function foo(){ return "foo" } export function bar(){ return "bar" } // src/index.js import { foo } from "./module" console.log(foo())
執(zhí)行 npx webpack -p(我們使用webpack 4,0配置,-p開啟生成模式 自動壓縮)
打包后我們在打包文件搜索 bar 沒有搜到,bar被刪除
我們將上面例子修改一下:
// src/module.js module.exports.foo = function (){ return "foo" } module.exports.bar = function (){ return "bar" } // src/index.js import { foo } from "./module" console.log(foo())
打包后搜索 bar 發(fā)現(xiàn)bar存在,webpack 并不支持對CommonJs 進行 Tree-shaking
pkg.modulewebpack 不支持 Commonjs Tree-shaking,但現(xiàn)在npm的包都是CommonJs規(guī)范的,這該怎么辦呢 ?如果我發(fā)了一個新包是 es module 規(guī)范, 但是如果代碼運行在 node 環(huán)境,沒有經(jīng)過打包 就會報錯
有一種按需加載的方案
全路徑導(dǎo)入,導(dǎo)入具體的文件:
// src/index.js import remove from "lodash/remove" import add from "lodash/add" console.log(remove(), add())
使用一個還好,如果用多個的話會有很多 import 語句
還可以使用插件如 babel-plugin-lodash, & lodash-webpack-plugin
但我們不能發(fā)一個庫就自己寫插件
這時就提出了在 package.json 加一個 module 的字段來指向 es module規(guī)范的文件,main -> CommonJs,那么module - es module pkg.module
webpack 與 rollup 都支持 pkg.module
加了 module 字段 webpack 就可以識別我們的 es module,但是還有一個問題就是 babel
我們一般使用 babel 都會排除 node_modules,所以我們這個 pkg.module 只是的 es6 module必須是編譯之后的 es5 代碼,因為 babel 不會幫我們編譯,我們的包就必須是 擁有 es6 module 規(guī)范的 es5 代碼
如果你使用了 presets-env 因為會把我們的代碼轉(zhuǎn)為 CommonJs 所以就要設(shè)置 "presets": [["env", {"modules":false}] 不將es module 轉(zhuǎn)為 CommonJs
webpack 與 rollup 的區(qū)別webpack 不支持導(dǎo)出 es6 module 規(guī)范,rollup 支持導(dǎo)出 es6 module
webpack 打包后代碼很多冗余無法直接看,rollup 打包后的代碼簡潔,可讀,像源碼
webpack 可以進行代碼分割,靜態(tài)資源處理,HRM,rollup 專注于 es module,tree-shaking更加強大的,精簡
如果是開發(fā)應(yīng)用可以使用 webpack,因為可以進行代碼分割,靜態(tài)資源,HRM,插件
如果是開發(fā)類似 vue,react 等類庫,rollup 更好一些,因為可以使你的代碼精簡,無冗余代碼,執(zhí)行更快,導(dǎo)出多種模塊語法
本文章介紹了 Commonjs 和 ES6 Module,導(dǎo)入導(dǎo)出的語法規(guī)則,路徑解析規(guī)則,兩者的區(qū)別,容易混淆的地方,在不同環(huán)境的區(qū)別,在不同環(huán)境的使用,Tree-shaking,與 webpack,rollup 的區(qū)別
希望您讀完文章后,能對前端的模塊化有更深的了解
ECMAScript? 2015 Language Specification sec-imports/sec-exports
MDN import
github nodejs lib/module
github nodejs node-eps/002-es-modules
nodejs docs modules
Understanding ECMAScript 6
ECMAScript 6 入門
es6-modules-final
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/101001.html
摘要:所有依賴這個模塊的語句,都定義在一個回調(diào)函數(shù)中,等到所有依賴加載完成之后前置依賴,這個回調(diào)函數(shù)才會運行。如果將前面的代碼改寫成形式,就是下面這樣定義了一個文件,該文件依賴模塊,當模塊加載完畢之后執(zhí)行回調(diào)函數(shù),這里并沒有暴露任何變量。 模塊化是我們?nèi)粘i_發(fā)都要用到的基本技能,使用簡單且方便,但是很少人能說出來但是的原因及發(fā)展過程。現(xiàn)在通過對比不同時期的js的發(fā)展,將JavaScript模...
摘要:本文從最簡單的模塊開始,然后主要從的模塊規(guī)范和的模塊機制對模塊進行梳理。對象的屬性模塊的識別符,通常是帶有絕對路徑的模塊文件名。返回一個對象,表示調(diào)用該模塊的模塊。表示模塊對外輸出的值。可見當刪除了相關(guān)模塊的緩存再一次加載時則不再有了。 前言 java有類文件,Python有import機制,Ruby有require等,而Javascript 通過標簽引入代碼的機制顯得雜亂無章,語言自...
摘要:我覺得那時他可能并沒有料到,這一規(guī)則的制定會讓整個前端發(fā)生翻天覆地的變化。前言 作為一名前端工程師,每天的清晨,你走進公司的大門,回味著前臺妹子的笑容,摘下耳機,泡上一杯茶,打開 Terminal 進入對應(yīng)的項目目錄下,然后 npm run start / dev 或者 yarn start / dev 就開始了一天的工作。 當你需要進行時間的轉(zhuǎn)換只需要使用 dayjs 或者 momentj...
摘要:本文主要介紹幾種模塊導(dǎo)入導(dǎo)出的方法。默認導(dǎo)出如果只在一個文件中提供了一個導(dǎo)出的口,就可以使用默認導(dǎo)出在中可以看到輸入同樣是模塊導(dǎo)入導(dǎo)出方法,使用的模塊方法,要比中的也就是模塊方法更加的差異非常大。 在開發(fā)中基本不會將所有的業(yè)務(wù)邏輯代碼放在一個JS文件中,特別是在使用前端框架,進行組件化開發(fā)中時,會復(fù)用相應(yīng)的組件。這時,就會用到模塊導(dǎo)入/導(dǎo)出的方法了。 當然,上面提到有模塊的概念,也是在...
摘要:先天就缺乏一項功能模塊通過標簽引入代碼的方式顯得雜亂無章,語言自身毫無組織和約束能力。與文件模塊區(qū)別地方在于它從內(nèi)存中加載緩存執(zhí)行結(jié)果的位置核心模塊在對象上,文件模塊在對象上未完待續(xù) javascript先天就缺乏一項功能:模塊 javasciprt 通過script標簽引入代碼的方式顯得雜亂無章,語言自身毫無組織和約束能力。人們不得不用命名空間等方式人為地約束代碼,以求達到安全和易用的...
閱讀 3616·2021-11-24 10:22
閱讀 3686·2021-11-22 09:34
閱讀 2480·2021-11-15 11:39
閱讀 1528·2021-10-14 09:42
閱讀 3662·2021-10-08 10:04
閱讀 1553·2019-08-30 15:52
閱讀 847·2019-08-30 13:49
閱讀 3015·2019-08-30 11:21