讀vue源碼看前端百態1--模塊化

Vue中的模塊化

vue2.0爲例html

在咱們執行npm run dev時,會看到package.json中,有vue

"dev": "rollup -w -c scripts/config.js --environment TARGET:web-full-dev"
複製代碼

根據 scripts/config.js 文件中的配置:node

// Runtime+compiler development build (Browser)
  'web-full-dev': {
    entry: resolve('web/entry-runtime-with-compiler.js'),
    dest: resolve('dist/vue.js'),
    format: 'umd',
    env: 'development',
    alias: { he: './entity-decoder' },
    banner
  }
複製代碼

這裏注意到format參數的值爲umd,git

注意看這個文件,在builds對象中還有github

// Runtime+compiler CommonJS build (CommonJS)
  'web-full-cjs': {
    entry: resolve('web/entry-runtime-with-compiler.js'),
    dest: resolve('dist/vue.common.js'),
    format: 'cjs',
    alias: { he: './entity-decoder' },
    banner
  },
    // Runtime+compiler CommonJS build (ES Modules)
  'web-full-esm': {
    entry: resolve('web/entry-runtime-with-compiler.js'),
    dest: resolve('dist/vue.esm.js'),
    format: 'es',
    alias: { he: './entity-decoder' },
    banner
  },
    // Runtime+compiler development build (Browser)
  'web-full-dev': {
    entry: resolve('web/entry-runtime-with-compiler.js'),
    dest: resolve('dist/vue.js'),
    format: 'umd',
    env: 'development',
    alias: { he: './entity-decoder' },
    banner
  },
複製代碼

咱們看到三種模塊: CommonJSES Modulesumdweb

什麼是模塊?

  • 將一個複雜的程序依據必定的規則(規範)封裝成幾個塊(文件), 並進行組合在一塊兒
  • 塊的內部數據與實現是私有的, 只是向外部暴露一些接口(方法)與外部其它模塊通訊

模塊化

接下來,咱們來學習下經常使用的模塊:express

CommonJS

經常使用的Node即是採用 CommonJS 模塊規範。每一個文件就是一個模塊,有本身的做用域。npm

服務器端,模塊的加載是運行時同步加載的;編程

瀏覽器端,模塊須要提早編譯打包處理。json

咱們一塊兒來看一看CommonJS的例子:

// example.js
var x = 5;
var addX = function (value) {
  return value + x;
};
module.exports.x = x;
exports.addX = addX;

//index.js
const example = require('./example.js')
console.log(example.x); // 5
console.log(example.addX(1)); // 6
example.x = 6
console.log(example.addX(1)); // 6


執行node index.js
複製代碼

CommonJS語法

暴露模塊:module.exports = value 或 exports.xxx = value

引入模塊:require(xxx),若是是第三方模塊,xxx爲模塊名,如require('express');若是是自定義模塊,xxx爲模塊文件路徑,如上例,require('./example.js')

CommonJS加載機制

引入的是暴露值的拷貝,因此要注意:

// example.js
var x = {
  name: 'kitty'
};
var outputX = function (value) {
  return x;
};
module.exports= {
  x,
  outputX
}

// index.js
const example = require('./example.js')
console.log(example.x); // { name: 'kitty' }
console.log(example.outputX()); // { name: 'kitty' }

example.x.name = 'cat'
console.log(example.x); // { name: 'cat' }
console.log(example.outputX()); //{ name: 'cat' }



執行node index.js
複製代碼

JS的拷貝是什麼?能夠查看個人JS開發者應懂的33個概念系列--原始類型2 && 值類型和引用類型3尋找答案!!!

CommonJS在瀏覽器的實現

// example.js 如上

// example2.js
module.exports = function() {
  console.log('example2')
}

// index.js
const example = require('./example.js')
const example2 = require('./example2.js')

example2();
console.log(example.x); 

// index.html
<html>
  <body>
    <script src="./index.js"></script>
  </body>
<html>

複製代碼

直接啓動index.html, 打開控制檯,會發現:

爲何會這樣呢?

上面說了,模塊須要提早編譯打包處理。 這裏咱們用browerify打包一下

// 全局安裝
 npm install browserify -g
 
// 根目錄下運行
browserify index.js -o bundle.js

// index.html替換script引用地址
<html>
  <body>
    <script src="./bundle.js"></script>
  </body>
<html>

複製代碼

能夠看一看打包事後的bundle.js

直接啓動index.html, 打開控制檯,會發現,哈哈,你成功了!!!

ES6模塊

ES6 模塊的設計思想是儘可能的靜態化,使得編譯時就能肯定模塊的依賴關係,以及輸入和輸出的變量。CommonJS 和 AMD 模塊,都只能在運行時肯定這些東西。好比,CommonJS 模塊就是對象,輸入時必須查找對象屬性。

是否是感受似懂非懂,沒有關係,咱們就是例子爲王。

ES6模塊語法

暴露模塊:export命令用於規定模塊的對外接口,好比export xxx, xxx是一個對象;或者指定默認輸出,用到export default命令,好比export default xxx

引入模塊:import命令用於引入其餘模塊提供的功能。好比import xxx from **,其中xxx是要加載的變量名或函數名;指定默認輸出時,xxx能夠爲匿名函數指定的任意名字。

ES6加載機制

CommonJS引入的是暴露值的拷貝,而ES6是對值的引用。

// example.js
export let x = 5;
export function addX () {
  return x++;
};


//index.js
import { x, addX } from './example.js'
console.log(x); // 5
addX()
console.log(x); // 6
複製代碼

執行node index.js,怎麼回事?

SyntaxError: Unexpected token import
複製代碼

這是由於node還沒有支持ES6的module方式,因此咱們須要babel-cli進行將ES6編譯爲ES5代碼。

  1. 更換目錄
example.js -> src/example.js
index.js -> src/index.js
複製代碼

2.全局安裝babel-cli

npm install babel-cli -g

3.定義.babelrc文件

{
   "presets": ["es2015"] 
}
複製代碼

4.使用ES6編譯爲ES5代碼:

babel src -d lib
複製代碼
  1. 好了,你能夠進入lib文件夾,運行 node index.js,就能夠輸出結果了。

ES6在瀏覽器的實現

// index.html
<html>
  <body>
    <script src="./lib/index.js"></script>
  </body>
<html>
複製代碼

有報錯了,可是是否是看起來很熟悉呢?

是的!

模塊須要提早編譯打包處理。

你知道怎麼作了?

答對了!

// 全局安裝
 npm install browserify -g
 
// 根目錄下運行
browserify lib/index.js -o bundle.js

// index.html替換script引用地址
<html>
  <body>
    <script src="./bundle.js"></script>
  </body>
<html>
複製代碼

固然能夠看看lib文件夾中的ES6轉換ES5代碼以及打包事後的bundle.js,這裏就不說了。 直接啓動index.html, 打開控制檯,會發現,哈哈,你成功了!!!

UMD

UMD (Universal Module Definition), 但願提供一個先後端跨平臺的解決方案(支持AMD與CommonJS模塊方式)。

CommonJS加載模塊是同步的,Node.js主要用於服務器編程,模塊文件通常已經存在於本地磁盤,因此加載起來比較快,因此CommonJS規範比較適用;

而AMD是非同步加載模塊,容許指定回調函數,在瀏覽器環境下,要從服務器加載模塊,這時就必須採用非同步模式,所以瀏覽器通常採用的是AMD規範。

AMD語法規範

暴露模塊

define([有依賴模塊,無依賴能夠省略],
function() { 
return 模塊
})
複製代碼

引入模塊

require([依賴模塊],callback)
複製代碼

AMD加載機制

RequireJS是一個工具庫,主要用於客戶端的模塊管理。它的模塊管理遵照AMD規範,RequireJS的基本思想是,經過define方法,將代碼定義爲模塊;經過require方法,實現代碼的模塊加載。

AMD在瀏覽器的實現

// example.js
define(function (){
  var add = function (x,y){
    return x+y;
  }
  return {
      add
  }
}

// index.js
(function () {
  require.config({
    paths: {
      example: './example'  // 不能寫example.js會報錯
    }
  })

  require(['example'], function(example) {
    console.log(example.add(2, 2))
  })
})()

// require.js
複製這個
https://requirejs.org/docs/release/2.3.6/minified/require.js的代碼

// index.html
<html>
  <body>
    <script data-main="./index.js" src="./require.js"></script>
  </body>
<html>
複製代碼

直接啓動index.html, 打開控制檯,會發現,哈哈,你成功了!!!

打開控制檯network,看到分步加載

回頭看一下Vue源碼中的umd格式的打包文件./dist/vue.runtime.js

UMD的實現很簡單:

  • 先判斷是否支持Node.js模塊格式(exports是否存在),存在則使用Node.js模塊格式。
  • 再判斷是否支持AMD(define是否存在),存在則使用AMD方式加載模塊。
  • 前兩個都不存在,則將模塊公開到全局(window或global)。
相關文章
相關標籤/搜索