前端工程化——模塊化概述

模塊化概述——「模塊化」只是思想

最主流的代碼整合方式,安裝功能不同劃分不同模塊。

  • 模塊化演變過程
  • 模塊化規範
  • 常用的模塊化打包工具
  • 基於模塊化工具構建現代WEB應用
  • 打包工具的優化技巧

模塊化的演進過程

Stage 1 - 文件劃分方式

完全依靠約定

├── index.html
├── module-01.js
└── module-02.js
  • 通過scriptsrc屬性引入模塊
  • 污染全局作用域,容易產生命名衝突
  • 模塊成員可以隨意修改
  • 無法管理模塊依賴關係

Stage 2 - 命名空間方式

依靠約定,模塊暴露全局對象, 所有成員都暴露在該對象下面,解決了污染全局作用域問題

var moduleA = {
    name: 'module-a'
    method1: function() {
        console.log(this.name + 'method1')
    }
    method2: function() {
        console.log(this.name + 'method2')
    }
}
  • 通過scriptsrc屬性引入模塊
  • 模塊成員可以隨意修改
  • 無法管理模塊依賴關係

Stage 3 - IIFE

立即執行函數方式,爲模塊提供私有空間。實現了私有成員的概念。通過自執行函數傳參的方式可以實現簡單的模塊化依賴處理

;
(function() {
    var name = 'module-a'

    function method1() {
        console.log(name + 'method1')
    }

    function method2() {
        console.log(name + 'method2')
    }
    window.moduleA = {
        method1: method1,
        method2: method2
    }
})(jQuery)
  • 通過scriptsrc屬性引入模塊
  • 無法管理模塊依賴關係

模塊化規範的出現

模塊化標準+模塊化加載器

  • 解決通過scriptsrc屬性引入模塊不受控制
  • 解決無法管理模塊依賴關係

CommonJs規範

以同步的模式加載模塊,在node環境中不會存在問題,但是在瀏覽器環境會導致效率低下

  • 一個文件就是一個模塊
  • 每個模塊都有單獨的作用域
  • 通過module.exports 導出成員
  • 通過require函數載入模塊

AMD規範 + Require.js

異步模式加載模塊

  • 使用相對複雜
  • 模塊js文件請求頻繁
  • 基本三方模塊都支持amd規範

define 定義模塊

// 參數1 模塊名字
// 參數2 聲明依賴項
// 參數3 callback函數 函數形參中接收定義依賴項 
// 返回函數值爲導出模塊
define('module1', ['jquery', './module2'], function($, module2) {
    return {
        start: function() {
            $('body').animate({
                margin: '200px'
            })
            module2()
        }
    }
})

require 加載模塊

require(['./module2'], function(module1) {
    module1.start()
})

模塊化標準規範——模塊化的最佳實踐

  • node

    遵循CommonJs規範

  • web環境

    遵循ES modules規範

ES modules

基本特性

  • 自動採用嚴格模式,忽略 ‘use strict’
  • 每個module 都運行在私用作用域當中
  • 通過CORS方式請求外部JavaScript模塊,不支持文件訪問
  • 標籤會延遲加載執行腳本

導入導出

直接導出

export const foo = 'es modules'
export function hello() {
    console.log('hello')
}
export class Person {}

文件末尾導出

const foo = 'es modules'

function hello() {
    console.log('hello')
}
class Person {}
export {
    foo,
    hello,
    Person
}

別名導出

const foo = 'es modules'
export {
    foo as myFoo
}

導出默認成員

const foo = 'es modules'
export default foo

常規引入

import {
    foo,
    hello,
    Person
} from './module.js'
console.log(foo)
console.log(hello)
console.log(Person)

別名處理

import {
    foo as myFoo
} from './module.js'
console.log(myFoo)

引入默認成員

import foo from './module.js'

導入導出注意事項

  • 末尾導出非對象字面量導出, 而是固定的語法
  • 導出的爲引用關係不是複製一個新的對象
  • 模塊引入是並不是對象解構,而是固定的語法
  • 模塊引入的模塊是隻讀的存在不能被修改

導入用法(原生)

  • 不能省略文件後綴名
  • 不能省略index

後續通過打包工具打包模塊時可以省略

  • 不能省略 ./ 相對路徑,否則視爲三方依賴包
  • 可以使用項目的絕對路徑
  • 可以使用網絡資源

導出一個模塊裏的所有方法

import * as mod from './module.js'
console.log(mod)
  • import 只能存在最頂層不能嵌套函數或if語句
  • import 的 from 後面不能是變量

動態導入

import('./module.js').then(module => {
    console.log(module)
})

默認成員與命名成員同時導入

import name, {
    age
} from './module.js'

導出導入成員

// 常用於index 文件,做導出零散文件使用
export {
    foo,
    bar
}from './module.js'
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章