JavaScript模块化

96 阅读3分钟

@TOC

CommonJS

  • 规范

    • 说明

      • wiki.commonjs.org/wiki/Module…
      • 每个文件都可当作一个模块
      • 在服务器端: 模块的加载是运行时同步加载的
      • 在浏览器端: 模块需要提前编译打包处理
    • 基本语法

      • 暴露模块

        • module.exports = value
        • exports.xxx = value
        • 问题: 暴露的模块到底是什么? :对象
      • 引入模块

        • require(xxx)

          • 第三方模块:xxx为模块名
          • 自定义模块: xxx为模块文件路径
  • 实现

    • 服务器端实现

    • 浏览器端实现

      • Browserify
      • browserify.org/
      • 也称为CommonJS的浏览器端的打包工具
    • 区别Node与Browserify

      • Node.js运行时动态加载模块(同步)
      • Browserify是在转译(编译)时就会加载打包(合并)require的模块

AMD

  • 规范

    • 说明

      • Asynchronous Module Definition(异步模块定义)
      • github.com/amdjs/amdjs…
      • 专门用于浏览器端, 模块的加载是异步的
    • 基本语法

      • 定义暴露模块

        • //定义没有依赖的模块 define(function(){ return 模块 })
        • //定义有依赖的模块 define(['module1', 'module2'], function(m1, m2){ return 模块 })
      • 引入使用模块

        • require(['module1', 'module2'], function(m1, m2){ 使用m1/m2 })
  • 实现(浏览器端)

CMD

  • 规范

    • 说明

      • Common Module Definition(通用模块定义)
      • github.com/seajs/seajs…
      • 专门用于浏览器端, 模块的加载是异步的
      • 模块使用时才会加载执行
    • 基本语法

      • 定义暴露模块

        • //定义没有依赖的模块 define(function(require, exports, module){ exports.xxx = value module.exports = value })
        • //定义有依赖的模块 define(function(require, exports, module){ //引入依赖模块(同步) var module2 = require('./module2') //引入依赖模块(异步) require.async('./module3', function (m3) {

      }) //暴露模块 exports.xxx = value })

      • 引入使用模块

        • define(function (require) { var m1 = require('./module1') var m4 = require('./module4') m1.show() m4.show() })
  • 实现(浏览器端)

ES6

  • 规范

    • 说明

    • 语法

      • 导出模块:

      1. 分多次导出模块的多个部分

        export class Emp{ }

        export function fun(){ }

        export var person = {};

      2. 一次导出模块的多个部分

        class Emp{ }

        function fun(){ }

        var person = {};

        export {Emp, fun, person}

      3. default导出(只能有一个)

        export default {}

      **导入模块

      import defaultModule from './myModule'; //导入默认的

      import {Emp} from './myModule'; //导入指定的一个

      import {Emp, person} from './myModule'; //导入指定的多个

      import * as allFromModule from './myModule'; //导入所有

      • 导出模块: export
      • 引入模块: import
  • 实现(浏览器端)

    • 使用Babel将ES6编译为ES5代码
    • 使用Browserify编译打包js

ES6-Babel-Browserify 使用教程

  1. 定义 package.json 文件
{
  "name" : "es6-babel-browserify",
  "version" : "1.0.0"
}
  1. 安装 babel-cli, babel-preset-es2015 和 browserify
  • npm install babel-cli browserify -g
    • npm install babel-preset-es2015 --save-dev
    • preset 预设(将 es6 转换成 es5 的所有插件打包)
  1. 定义.babelrc 文件 run contorl
    {
      "presets": ["es2015"]
    }
    
  2. 编码
  • js/src/module1.js 分别暴露

    export function foo() {
      console.log('module1 foo()');
    }
    export function bar() {
      console.log('module1 bar()');
    }
    export const DATA_ARR = [1, 3, 5, 1]
    
  • js/src/module2.js 统一暴露

    let data = 'module2 data'
    
    function fun1() {
      console.log('module2 fun1() ' + data);
    }
    
    function fun2() {
      console.log('module2 fun2() ' + data);
    }
    
    export {fun1, fun2}
    
  • js/src/module3.js

    export default {
      name: 'Tom',
      setName: function (name) {
        this.name = name
      }
    }
    
  • js/src/app.js

    import {foo, bar} from './module1'
    import {DATA_ARR} from './module1'
    import {fun1, fun2} from './module2'
    import person from './module3'
    
    import $ from 'jquery'
    
    $('body').css('background', 'red')
    
    foo()
    bar()
    console.log(DATA_ARR);
    fun1()
    fun2()
    
    person.setName('JACK')
    console.log(person.name);
    
  1. 编译
  • 使用 Babel 将 ES6 编译为 ES5 代码(但包含 CommonJS 语法) : babel js/src -d js/lib
  • 使用 Browserify 编译 js : browserify js/lib/app.js -o js/lib/bundle.js
  1. 页面中引入测试
<script type="text/javascript" src="js/lib/bundle.js"></script>
  1. 引入第三方模块(jQuery) 1). 下载 jQuery 模块:
    • npm install jquery@1 --save 2). 在 app.js 中引入并使用
    import $ from 'jquery'
    $('body').css('background', 'red')
    

案例

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>05_load script</title>
</head>
<body>
<!--
  1. 一个页面需要引入多个js文件
  2. 问题:
    1). 请求过多
    2). 依赖模糊
    3). 难以维护
  3. 这些问题可以通过现代模块化编码和项目构建来解决
-->

<script type="text/javascript" src="module1.js"></script>
<script type="text/javascript" src="module2.js"></script>
<script type="text/javascript" src="module4.js"></script>
<script type="text/javascript" src="module3.js"></script>
<script type="text/javascript" src="../04_IIFE模式增强/jquery-1.10.1.js"></script>
<script type="text/javascript" src="../04_IIFE模式增强/test4.js"></script>
<script type="text/javascript">
  module.foo()
</script>
</body>
</html>

npm i browserify -g //打包需要的工具 全局安装 npm install browserify --save-dev // 局部安装 开发依赖 -dev browserify js/src/app.js -o js/dist/index.js // 打包文件的命令

 /**
  1. 定义暴露模块:
    module.exports = value;
    exports.xxx = value;
  2. 引入模块:
    var module = require(模块名或模块路径);
 */
 
/* 
  npm i browserify -g   
  npm install browserify --save-dev
  browserify js/src/app.js  -o  js/dist/index.js // 打包文件的命令 
*/

"use strict"
//引用模块
let module1 = require('./modules/module1')
let module2 = require('./modules/module2')
let module3 = require('./modules/module3')

let uniq = require('uniq')
let fs = require('fs')

//使用模块
module1.foo()
module2()
module3.foo()
module3.bar()

console.log(uniq([1, 3, 1, 4, 3]))

fs.readFile('app.js', function (error, data) {
  console.log(data.toString())
})

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <!-- <script type="text/javascript" src="js/src/app.js"></script> -->
    <!-- <script type="text/javascript" src="js/dist/bundle.js"></script> -->
    <script type="text/javascript" src="js/dist/index.js"></script>
</body>
</html>