在開發(fā)Electron
程序時无切,在引入jQuery
和Bootstrap
后荡短,控制臺報錯:
Uncaught TypeError: Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.
at Object.jQueryDetection (bootstrap.min.js:6)
at bootstrap.min.js:6
at bootstrap.min.js:6
at bootstrap.min.js:6
而反復(fù)查看代碼沒發(fā)現(xiàn)問題丐枉,引用的順序沒有問題:
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap.min.js"></script>
后在網(wǎng)上找到了一些方法,解決了我的疑惑掘托。
方法一
在引入jQuery
之前瘦锹,添加如下代碼:
<script>
if (typeof module === 'object') {window.module = module; module = undefined;}
</script>
方法二
使用require
方式引入jquery
:
window.$ = window.jQuery = require('./js/jquery.min.js')
雖然問題是解決了,但是是什么引發(fā)了這個問題呢闪盔?
經(jīng)過深入了解弯院,發(fā)現(xiàn)原來electron
里面還是和瀏覽器有區(qū)別的。在electron
里面使用的是CommonJS
標(biāo)準(zhǔn)泪掀,這也是后端服務(wù)器采用的標(biāo)準(zhǔn)听绳,而在jQuery
中有如下代碼:
if ( typeof module === "object" && typeof module.exports === "object" ) {
// set jQuery in `module`
} else {
// set jQuery in `window`
}
判斷如果在CommonJS
中,jQuery
就綁定到module
下异赫,否者就綁定到window
下椅挣,我們經(jīng)常使用的$
就是在window
的下。
而Bootstrap
是一個(首發(fā)共眾號)前端工具塔拳,它依賴jQuery
鼠证,直接從window
下有沒有jQuery/$
來判斷有沒有jQuery
,而在這里就行(正義的程序猿)不通了靠抑,因為jQuery
是在module
下的量九,所以就有了如上的兩種方法,個人更傾向于第二種方法。
有沒有其他方法荠列?有类浪!
方法三
因為electron
中集成了node
相關(guān)的東西,可以把這個集成關(guān)閉或者把相關(guān)對象綁定到新的對象上:
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
nodeIntegration: false // 重點是這個
}
})
上面這種方式弯予,window
對象下就沒有module
了戚宦。
當(dāng)然我們也可以把綁定的對象替換掉,這樣也能使用node
相關(guān)的API
:
<head>
<script>
window.nodeRequire = require;
delete window.require;
delete window.exports;
delete window.module;
</script>
<script type="text/javascript" src="jquery.js"></script>
</head>
這只是一種解決思路锈嫩,不建議大家這么做受楼。
既然都談到CommonJS
了,有必要進一步了解前端的幾個規(guī)范呼寸。
CommonJs艳汽,AMD和CMD
-
CommonJS
是nodejs
也就是服務(wù)器端廣泛使用的模塊化機制,模塊必須通過module.exports 導(dǎo)出對外的變量或接口对雪,通過require()
來導(dǎo)入其他(首發(fā)公zhong號)模塊的(正義的程序猿河狐,歡迎關(guān)注)輸出到當(dāng)前模塊作用域中,此方式是同步的 -
AMD
是RequireJS
在推廣過程中對模塊定義的規(guī)范化產(chǎn)出瑟捣,提前執(zhí)行(異步加載:依賴先執(zhí)行)+延遲執(zhí)行 -
CMD
是SeaJS
在推廣過程中對模塊定義的規(guī)范化產(chǎn)出馋艺,延遲執(zhí)行(運行到需加載,根據(jù)順序執(zhí)行)
CommonJS
CommonJS
模塊加載是同步的迈套,后面的模塊必須等前面的加載完成才能執(zhí)行捐祠。
定義模塊:
// 模塊 a.js
const name = 'foo'
module.exports = {
name,
text: 'bar'
}
加載模塊:
// 模塊 b.js
// 引用核心模塊或者第三方包模塊,不需要寫完整路徑
const path = require('path');
// 引用自定義模塊可以省略.js
const { name, text } = require('./a');
console.log(name, text);
// 輸出 foo bar
CommonJS模塊的加載(首發(fā)公zhong號)機制是桑李,輸入的是被輸出的值的拷貝踱蛀。也就是說,一旦輸出一個值贵白,模塊內(nèi)部的變化就影響不到這個值率拒。(正義的程序猿)看如下例子:
// b.js
let age = 1;
setTimeout(() => {
age = 18;
}, 10);
module.exports = {
age
}
// a.js
const b = require('./b');
console.log(b.age);
setTimeout(() => {
console.log(b.age);
console.log(require('./b').age);
}, 100);
// 執(zhí)行:node a.js
// 執(zhí)行結(jié)果:
// 1
// 1
// 1
還有,CommonJS
模塊重復(fù)引入的模塊并不會重復(fù)執(zhí)行禁荒,再次獲取模塊只會獲得之前獲取到的模塊的緩存猬膨。
AMD
全稱:Asynchronous Module Definition
,中文翻譯:異步模塊定義呛伴,javascript
原生不支持這種規(guī)范勃痴,使用AMD規(guī)范進行頁面開發(fā)需要用到對應(yīng)的庫函數(shù),鼎鼎大名的就是RequireJS
磷蜀,
定義模塊:
// 獨立模塊
define(function(){
...
return {
//返回接口
}
})
// 非獨立模塊
define(['foo','bar'],function(foo, bar){
...
return {
//返回接口
}
})
獨立模塊即定義的模塊不依賴其他模塊召耘,非獨立模塊就是會依賴其他模塊。我們定義的模塊依賴foo
和bar
褐隆,第二個參數(shù)是一個函數(shù)污它,僅當(dāng)依賴加載成功后才會調(diào)用,函數(shù)的參數(shù)與前面的依賴數(shù)組一一對應(yīng),函數(shù)必須返回一個對象衫贬,給其他模塊調(diào)用德澈。
加載模塊:
AMD
加載模塊也是用require
,由于是異步的所以只能用回調(diào)函數(shù)的方式:
require(['foo','bar'], function(foo,bar){
...
})
回調(diào)函數(shù)中才能使用依賴的模塊固惯,這里是在定義的時候加載模塊了梆造,相當(dāng)于把依賴前置。
require()
里面可以配置一些參數(shù):
require.config({
paths: {
"backbone": "vendor/backbone",
"underscore": "vendor/underscore"
},
shim: {
"backbone": {
deps: [ "underscore" ],
exports: "Backbone"
},
"underscore": {
exports: "_"
}
}
});
- paths: 指定模塊的位置葬毫,可以是文件路徑镇辉,也可以是一個網(wǎng)址
- shim: 有些庫不兼容
AMD
的寫法,可以配置shim
來解決贴捡,可以理解成“墊片”忽肛,幫助require.js
加載非AMD規(guī)范的庫
CMD
即Common Module Definition
通用模塊定義,這個規(guī)范也是國內(nèi)發(fā)展起來的烂斋,有個瀏覽器的實現(xiàn)SeaJS
屹逛,CMD
和AMD
要解決的問題都是一樣的,只不過在模塊定義方式和模塊加載(可以說運行汛骂、解析)時機上有所不同罕模。
和其他規(guī)范一樣,CMD
中也是一個模塊一個文件:
define(function(require, exports, module) {
// 模塊代碼
});
require
是可以把其他模塊導(dǎo)入進來的一個參數(shù);而exports
是可以把模塊內(nèi)的一些屬性和方法導(dǎo)出的;module
是一個對象帘瞭,上面存儲了與當(dāng)前模塊相關(guān)聯(lián)的一些屬性和方法淑掌。
AMD
是依賴關(guān)系前置,在定義模塊的時候就要聲明其依賴的模塊图张,CMD
是按需加載依賴锋拖,只有在用到某個模塊的時候再去require
诈悍,看看CMD
的例子:
// model1.js
define(function (require, exports, module) {
console.log('model1 entry');
exports.getHello = function () {
return 'model1';
}
});
// model2.js
define(function (require, exports, module) {
console.log('model2 entry');
exports.getHello = function () {
return 'model2';
}
});
// main.js
define(function(require, exports, module) {
var model1 = require('./model1'); //在需要時聲明
console.log(model1.getHello());
var model2 = require('./model2'); //在需要時聲明
console.log(model2.getHello());
});
<script src="sea.js"></script>
<script>
seajs.use('./main.js')
</script>
CommonJS
主要用于服務(wù)端祸轮,模塊文件都存在本地硬盤,所以加載起來比較快侥钳,不用考慮用異步加載适袜,但是在瀏覽器中,受限于網(wǎng)絡(luò)原因舷夺,更合理的方案應(yīng)該是異步加載苦酱。為了方便模塊化開發(fā),這時武林中出現(xiàn)了AMD
和CMD
兩大門派给猾,分別代表了兩種不同的思想疫萤,一是依賴前置,二是按需加載依賴敢伸,各有利弊扯饶,這兩大門派都像爭奪武林盟主,按理說是要比武論高下的,但半路殺出個程咬金尾序,選舉委員會直接自己推了一個規(guī)范:ES Module
钓丰,告知天下以后要聽ES Module
的,他才是大哥每币。
這小子又是誰携丁?
ES Module
ES modules(ESM)是 JavaScript 官方的標(biāo)準(zhǔn)化模塊系統(tǒng),能和CommonJS
混合使用兰怠,意味著能在node
環(huán)境下執(zhí)行梦鉴,因為他是標(biāo)準(zhǔn),所以未來很多瀏覽器都會支持揭保。
模塊定義:
// module.js
export function name() {
return 'this is name';
}
export function foo() {
return 'foooooo';
}
模塊加載:
// index.js
import { name, foo } from './module.js';
console.log(name(), foo());
加載模塊的方式還有很多種尚揣,比如:
// 加載單個模塊
import {sum} from './example.js'
// 加載多個
import {sum,multiply} from './example.js'
// 導(dǎo)入整個模塊,別創(chuàng)建一個別名
import * as example from './example.js'
在ESM
中模塊導(dǎo)出是值的引用掖举,看如下例子:
// b.js
export let age = 1;
setTimeout(() => {
age = 2;
}, 10);
// a.js
import { age } from './b.js';
console.log(age);
setTimeout(() => {
console.log(age);
import('./b.js').then(({ age }) => {
console.log(age);
})
}, 100);
// 執(zhí)行結(jié)果:
// 1
// 2
// 2
import/export
使用又一個限制快骗,就是不能在其他語句/表達式的內(nèi)部使用,比如if
語句里面塔次,所以一般都在最底部方篮,原因是ESM
使用javascript引擎靜態(tài)分析。
至此励负,ESM
已經(jīng)是事實上的盟主藕溅,使用該規(guī)范無論是node
環(huán)境還是瀏覽器環(huán)境都能很好兼容,而且前端也不要再引入requirejs
或sea.js
來進行模塊開發(fā)继榆。
以上是我對javascript
模塊開發(fā)的一些筆記巾表,如有問題可以地下留言。
參考:
http://www.reibang.com/p/d67bc79976e6
https://blog.csdn.net/crystal6918/article/details/74906757
https://cloud.tencent.com/developer/article/1589084