javascript中的模塊化
文章目錄
ES6之前,js沒有出現模塊化系統。
- JS主要在前端的瀏覽器中使用,js文件下載緩存到客戶端,在瀏覽器中執行。比如簡單的表單本地驗證,漂浮一個廣告。服務器端使用ASP、JSP等動態網頁技術,將動態生成數據嵌入一個HTML模板,裏面夾雜着JS後使用
<script>
標 籤,返回瀏覽器端。這時候的JS只是一些簡單函數和語句的組合。 - 2005年之後,隨着Google大量使用了AJAX技術之後,可以異步請求服務器端數據,帶來了前端交互的巨大變化。 前端功能需求越來越多,代碼也越來也多。隨着js文件的增多,災難性的後果產生了。由於習慣了隨便寫,js腳本 中各種全局變量污染,函數名衝突,無法表達腳本之間的依賴關係,因爲都是用腳本文件先後加載來實現的。亟待 模塊化的出現。
- 2008年V8引擎發佈,2009年誕生了Nodejs,支持服務端JS編程,但沒有模塊化是不可以的。
- 之後產生了commonjs規範。commonjs規範,使用全局require函數導入模塊,使用exports導出變量。爲了將這種模塊化規範向前端開發遷移,又演化出其它的規範。例如AMD。
- AMD(Asynchronous Module Definition)異步模塊定義,使用異步方式加載模塊,模塊的加載不影響它後面語 句的執行。所有依賴這個模塊的語句,都需要定義在一個回調函數,回調函數中使用模塊的變量和函數,等模塊加 載完成之後,這個回調函數纔會執行,就可以安全的使用模塊的資源了。其實現就是AMD/RequireJs。AMD雖然是 異步,但是會預先加載和執行。
- CMD(Common Module Definition),使用seajs,作者是淘寶前端玉伯,兼容幷包解決了RequireJs的問題。 CMD推崇as lazy as possible,儘可能的懶加載。
- 由於社區的模塊化呼聲很高,ES6開始提供支持模塊的語法,但是瀏覽器目前支持還不夠。
ES6模塊化
- import語句,導入另一個模塊導出的綁定。
- export語句,從模塊中導出函數、對象、值的,供其他模塊import導入用。
導出
- 建立一個模塊目錄src,然後在這個目錄下新建一個moda.js,內容如下:
//缺省導出
export default class A{
constructor(x){
this.x = x;
}
show(){
console.log(this.x)
}
}
//導出函數
export function foo(){
console.log('foo function');
}
//導出常量
export const CONSTA = 'aaa';
- 在src目錄中建立text.js導入moda.js中的內容,並使用,如下:
import {A,foo} from "./moda"
import * as mod_a from "./moda"
VS Code可以很好的語法支持了,但是運行環境,包括V8引擎,都不能很好的支持模塊化語法。
轉譯工具
轉譯就是從一種語言代碼轉換到另一個語言代碼,當然也可以從高版本轉譯到低版本的支持語句。
由於JS存在不同版本,不同瀏覽器兼容的問題。可以使用transpiler轉譯工具解決。
babel
- 開發中可以使用較新的ES6語法,通過轉譯器轉換爲指定的某些版本代碼。
- 官網https://babeljs.io/
- 參考文檔https://babeljs.io/docs/en/6.26.3/index.html注意當前版本7.x已經有了較大的變化,請參看6.x文檔
- 在
Try it out
。中可測試代碼
預設
- 有如下一些預設presets,我們先看看有哪些,一會兒再進行預設的安裝和配置
- presets:
babel-preset-env
當前環境支持的代碼,新target
- ES2015轉碼規則
npm install --save-dev babel-preset-es2015
- react轉碼規則
npm install --save-dev babel-preset-react
- ES7不同階段語法提案的轉碼規則(共4個階段),選裝一個
npm install --save-dev babel-preset-stage-0
npm install --save-dev babel-preset-stage-1
npm install --save-dev babel-preset-stage-2
npm install --save-dev babel-preset-stage-3
- presets:
離線轉譯安裝配置
1.初始化npm
- 打開cmd命令窗口,進入項目根目錄。輸入
npm init
初始化項目根目錄
PS D:\MyPythonUse\WebJS> npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help json` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (webjs) test
version: (1.0.0)
description: babel
entry point: (test.js)
test command:
git repository:
keywords:
author: xdd
license: (ISC)
About to write to D:\MyPythonUse\WebJS\package.json:
{
"name": "test",
"version": "1.0.0",
"description": "babel",
"main": "test.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "xdd",
"license": "ISC"
}
Is this OK? (yes) yes
PS D:\MyPythonUse\WebJS>
- 在項目根目錄下會生成package.json文件,內容就是上面花括號的內容。
2.設置鏡像
.npmrc
文件。修改npm安裝軟件時默認連接倉庫爲淘寶的npm倉庫。- 可以放到npm的目錄下npmrc文件中
- 可以放到用戶家目錄中
- 可以放到項目根目錄中
- 本次放到項目根目錄黃總,內容如下:
- 在項目更目錄中新建一個文件名爲
.npmrc
的文件。寫入registry=https://registry.npm.taobao.org
$ echo "registry=https://registry.npm.taobao.org" > .npmrc
- 在項目更目錄中新建一個文件名爲
3.安裝
- 項目根目錄下執行
npm install babel-core babel-cli --save-dev
- –save–dev說明:當你爲你的模塊安裝一個依賴模塊時,正常情況下你得先安裝他們(在模塊根目錄下npm install module-name),然 後連同版本號手動將他們添加到模塊配置文件package.json中的依賴裏(dependencies)。開發用。–save和–save-dev可以省掉你手動修改package.json文件的步驟。
spm install module-name --save
自動把模塊和版本號添加到dependencies部分spm install module-name --save-dev
自動把模塊和版本號添加到devdependencies部分
- 安裝完後,在項目根目錄下出現
node_modules
目錄 ,裏面有babel相關模塊及依賴的模塊。
4.修改package.json
- 修改package.json文件中scripts的部分,添加
"build": "babel src -d lib"
。"build": "babel src -d lib"
從src目錄中轉譯後的文件輸出到lib目錄- 修改
"license": "ISC"
爲"license": "MIT"
5.準備目錄
- 項目根目錄下建立src和lib目錄。
- src是源碼文件目錄。
- lib是目標目錄。
6.配置babel和安裝依賴
- 在目錄根目錄下創建
.babelrc
文件,Json格式。
{
"presets":["env"]
}
env
可以根據當前環境自動選擇。- 安裝依賴
npm install babel-preset-env --save-dev
7.準備js文件
-
在src中的mod.js
// 缺省導出 export default class A{ constructor(x){ this.x = x; } show(){ console.log(this.x); } } export function foo(){ console.log('foo function'); }
-
在src目錄下的index.js
import A,{foo} from './mod' var a = new A(100); a.show(); foo();
- index.js這段代碼在vs Code的環境下執行出錯。估計很難有能夠正常運行的環境。所以,要轉義爲ES5的代碼。
8.轉義js文件
-
在項目根目錄下執行命令
npm run build
$ npm run build > [email protected] build D:\MyPythonUse\WebJS > babel src -d lib src\index.js -> lib\index.js src\mod.js -> lib\mod.js gdy@gdy MINGW64 /d/MyPythonUse/WebJS $
- 可以看到兩個文件被轉義,運行轉義文件
node lib/index.js
$ node lib/index.js 100 foo function gdy@gdy MINGW64 /d/MyPythonUse/WebJS
- 使用babel等轉譯器轉譯JS非常流行。開發者可以在高版本中使用新的語法特性,提高開發效率,把兼容性問題交給轉譯器處理。
- 可以看到兩個文件被轉義,運行轉義文件
9.可能出現的錯誤
.babelrc
文件錯誤。重新刪除.babelrc
文件後再重新建立一個該文件。
-
錯誤信息
gdy@gdy MINGW64 /d/MyPythonUse/WebJS $ npm run build > [email protected] build D:\MyPythonUse\WebJS > babel src -d lib SyntaxError: D:\MyPythonUse\WebJS\.babelrc: Error while parsing JSON - Unexpected '�' at line 1 column 2 of the JSON5 data. Still to read: "��{\u0000\r\u0000\n\u0000\t\u0000\"\u0000p\u0000r\u0000e\u0000s\u0000" at error (D:\MyPythonUse\WebJS\node_modules\json5\lib\json5.js:56:25) at word (D:\MyPythonUse\WebJS\node_modules\json5\lib\json5.js:393:13) at value (D:\MyPythonUse\WebJS\node_modules\json5\lib\json5.js:493:56) at Object.parse (D:\MyPythonUse\WebJS\node_modules\json5\lib\json5.js:508:18) at ConfigChainBuilder.addConfig (D:\MyPythonUse\WebJS\node_modules\babel-core\lib\transformation\file\options\build-config-chain.js:150:65) at ConfigChainBuilder.findConfigs (D:\MyPythonUse\WebJS\node_modules\babel-core\lib\transformation\file\options\build-config-chain.js:96:16) at buildConfigChain (D:\MyPythonUse\WebJS\node_modules\babel-core\lib\transformation\file\options\build-config-chain.js:61:13) at OptionManager.init (D:\MyPythonUse\WebJS\node_modules\babel-core\lib\transformation\file\options\option-manager.js:354:58) at File.initOptions (D:\MyPythonUse\WebJS\node_modules\babel-core\lib\transformation\file\index.js:212:65) at new File (D:\MyPythonUse\WebJS\node_modules\babel-core\lib\transformation\file\index.js:135:24) npm ERR! code ELIFECYCLE npm ERR! errno 1 npm ERR! [email protected] build: `babel src -d lib` npm ERR! Exit status 1 npm ERR! npm ERR! Failed at the [email protected] build script. npm ERR! This is probably not a problem with npm. There is likely additional logging output above. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\gdy\AppData\Roaming\npm-cache\_logs\2019-07-06T13_06_31_034Z-debug.log
-
解決辦法
gdy@gdy MINGW64 /d/MyPythonUse/WebJS $ rm .babelrc gdy@gdy MINGW64 /d/MyPythonUse/WebJS $ echo "{\"presets\": [\"env\"]}" >.babelrc gdy@gdy MINGW64 /d/MyPythonUse/WebJS $ cat .babelrc {"presets": ["env"]} gdy@gdy MINGW64 /d/MyPythonUse/WebJS $ npm run build > [email protected] build D:\MyPythonUse\WebJS > babel src -d lib src\index.js -> lib\index.js src\mod.js -> lib\mod.js gdy@gdy MINGW64 /d/MyPythonUse/WebJS $
導入導出
- 說明:導出代碼都在src/mod.js中,導入代碼都寫在src/index.js中。
缺省導入導出
- 只允許一個缺省導出,缺省導出可以是變量、函數、類,但不能使用let、var、const關鍵字作爲默認導出。
- 缺省導入,不需要在import後使用花括號。
- 缺省導入的時候,可以自己重新命名,可以不需要和缺省導出時的名稱一致,但最好一致。
- 可以使用
import * as 新名稱 from '模塊'
語法來導入所有導出。
-
src/mod.js中
//缺省導出 匿名函數 export default function() { console.log('我是缺省導出') }
-
src/index.js中
//缺省導入 import defaultFunc from './mod' defaultFunc();
-
控制檯執行命令:
$ npm run build > [email protected] build D:\MyPythonUse\WebJS > babel src -d lib src\index.js -> lib\index.js src\mod.js -> lib\mod.js gdy@gdy MINGW64 /d/MyPythonUse/WebJS $ node lib/index.js 我是缺省導出 gdy@gdy MINGW64 /d/MyPythonUse/WebJS $
-
第二種示例
// mod模塊中 // 缺省導出 命名函數 export default function xyz(){ console.log('default export function') } // index模塊中 //缺省導入 import defaultFunc from './mod' defaultFunc();
-
命名導入和導出
-
src/mod.js中
/** * 導出舉例 */ //缺省導出 類 export default class { constructor(x){ this.x = x; } show(){ console.log(this.x); } } // 命名導出 函數 export function foo(){ console.log('我是函數foo'); } // 定義函數 function bar(){ console.log("我是函數bar()"); } // 變量常量定義 let x = 100; var y = 200; const z = 300; //導出 export {bar,x,y,z}
-
src/index.js中
/** * 導入舉例 * as 設置別名 */ import defaultCls,{foo,bar,x,y,z as CONST_C} from './mod'; foo(); bar(); console.log(x); //x只讀,不可修改,x++會出現異常 console.log(y); //y只讀 console.log(CONST_C); let fun =new defaultCls(1000); fun.show();
-
cmd命令行中執行
$ npm run build > [email protected] build D:\MyPythonUse\WebJS > babel src -d lib src\index.js -> lib\index.js src\mod.js -> lib\mod.js gdy@gdy MINGW64 /d/MyPythonUse/WebJS $ node ./lib/index.js 我是函數foo 我是函數bar() 100 200 300 1000 gdy@gdy MINGW64 /d/MyPythonUse/WebJS $
-
在index.js文件中也可以使用下面形式,導入所有導出,但是會定義一個新的名詞空間。使用名詞空間可以避免衝突。
import * as newmod from './mod'; newmod.foo(); newmod.bar(); new newmod.default(2000).show();