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

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

最主流的代码整合方式,安装功能不同划分不同模块。

  • 模块化演变过程
  • 模块化规范
  • 常用的模块化打包工具
  • 基于模块化工具构建现代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'
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章