1. 程式人生 > >vue2.x原始碼解析三——原始碼構建

vue2.x原始碼解析三——原始碼構建

1.Rollup介紹

1.2rollup和webpack都是區別

webpack更加強大 可以將圖片,css等都解析為js。
rollup 更適合於js庫的編譯,只適用於js部分,別的檔案是不管的,並且更加友好

2.Vue.js 原始碼構建指令碼

通常一個基於 NPM 託管的專案,在它的根目錄下都會有一個 package.json 檔案,它是對專案的描述檔案,它的內容實際上是一個標準的 JSON 物件。

我們學習閱讀一個專案的原始碼時,首先當然要看它的package.json檔案。這裡面有專案的依賴,有開發環境、生產環境等編譯的啟動指令碼,有專案的許可資訊等。

vue的 package.json我們將其簡寫為:

{
  "name": "vue",
  "version": "2.5.17-beta.0",
  "description": "Reactive, component-oriented view layer for modern web interfaces.",
  "main": "dist/vue.runtime.common.js",
  "module": "dist/vue.runtime.esm.js",
  "script": {
    "build": "node scripts/build.js",
    "build:ssr": "npm run build -- web-runtime-cjs,web-server-renderer"
, "build:weex": "npm run build --weex" }
}

我想前端都應該明白其中的含義,我們主要來看作為 NPM 的執行指令碼的script 欄位
這裡總共有 3 條命令,作用都是構建 Vue.js,後面 2 條是在第一條命令的基礎上,新增一些環境引數。

當在命令列執行 npm run build 的時候,實際上就會執行 node scripts/build.js,接下來我們來看看它實際是怎麼構建的。

3.構建過程

構建執行 node scripts/build.js

3.1 scripts檔案下build.js 中:

3.1.1 大致過程

  • 1.通過let builds = require(‘./config’).getAllBuilds()拿到每一種vue.js的相關配置

  • 2.對所有的配置進行過濾,將package.json中的命令,例如npm run build –
    web-runtime-cjs,web-server-renderer,就是過濾掉不是web-runtime-cjs,web-server-renderer的,如果沒有傳引數,例如npmrun
    build 那麼就只將weex過濾,只打包web平臺

if (process.argv[2]) {
  const filters = process.argv[2].split(',')
  builds = builds.filter(b => {
    return filters.some(f => b.output.file.indexOf(f) > -1 || b._name.indexOf(f) > -1)
  })
} else {
  // filter out weex builds by default
  builds = builds.filter(b => {
    return b.output.file.indexOf('weex') === -1
  })
}
  • 3.對過濾後的vue.js檔案進行build,檔案中用的就是build函式

3.1.2 完整程式碼:

// 引入包
const fs = require('fs')
const path = require('path')
const zlib = require('zlib')
const rollup = require('rollup')
const uglify = require('uglify-js')

if (!fs.existsSync('dist')) {
  fs.mkdirSync('dist')
}

// 拿到所有的構建的配置
let builds = require('./config').getAllBuilds()

// 將配置進行過濾,將package.json中的命令,例如npm run build -- web-runtime-cjs,web-server-renderer,就是過濾掉不是web-runtime-cjs,web-server-renderer的,如果沒有傳引數,例如npm run build 那麼就只將weex過濾,只打包web平臺
if (process.argv[2]) {
  const filters = process.argv[2].split(',')
  builds = builds.filter(b => {
    return filters.some(f => b.output.file.indexOf(f) > -1 || b._name.indexOf(f) > -1)
  })
} else {
  // filter out weex builds by default
  builds = builds.filter(b => {
    return b.output.file.indexOf('weex') === -1
  })
}

// 過濾後再通過build函式進行真正的構建過程
build(builds)

// build 在去呼叫buildEntry函式
function build (builds) {
  let built = 0
  const total = builds.length
  const next = () => {
    buildEntry(builds[built]).then(() => {
      built++
      if (built < total) {
        next()
      }
    }).catch(logError)
  }
  next()
}


function buildEntry (config) {
  const output = config.output
  const { file, banner } = output
  const isProd = /min\.js$/.test(file)
  return rollup.rollup(config)
    .then(bundle => bundle.generate(output))
    .then(({ code }) => {
      // 如果是 min.js 結尾的js就再進行一次壓縮
      if (isProd) {
        var minified = (banner ? banner + '\n' : '') + uglify.minify(code, {
          output: {
            ascii_only: true
          },
          compress: {
            pure_funcs: ['makeMap']
          }
        }).code
        // 呼叫write方法
        return write(file, minified, true)
      } else {
        return write(file, code)
      }
    })
}

function write (dest, code, zip) {
  return new Promise((resolve, reject) => {
    function report (extra) {
      console.log(blue(path.relative(process.cwd(), dest)) + ' ' + getSize(code) + (extra || ''))
      resolve()
    }

  // 呼叫fs.writeFile方法將檔案生成到dist目錄下
    fs.writeFile(dest, code, err => {
      if (err) return reject(err)
      if (zip) {
        zlib.gzip(code, (err, zipped) => {
          if (err) return reject(err)
          report(' (gzipped: ' + getSize(zipped) + ')')
        })
      } else {
        report()
      }
    })
  })
}

function getSize (code) {}

function logError (e) {}

function blue (str) {}

3.2 scripts檔案下config.js:

build.js在該檔案中拿到了每一種vue.js的相關配置

3.2.1 大致過程

  • 1.通過const aliases = require(‘./alias’),拿到大部分檔案的路徑
  • 2.對resolve方法進行封裝,配合aliases檔案,其實就是獲取檔案的路徑,如下面的entry入口檔案
const resolve = p => {
  const base = p.split('/')[0]
  if (aliases[base]) {
    return path.resolve(aliases[base], p.slice(base.length + 1))
  } else {
    return path.resolve(__dirname, '../', p)
  }
}
  • 3.const builds = {},不同版本vue.js的配置
  • 4.function genConfig (name){} 真正的構建工具rollup的配置,每一種vue.js就會對用不同的配置
  • 5.將通過vue.js的配置而得到的rollup的具體配置輸出
if (process.env.TARGET) {
  module.exports = genConfig(process.env.TARGET)
} else {
  exports.getBuild = genConfig
  exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}

3.2.3 具體程式碼:

引入的檔案或元件
const path = require('path')
const buble = require('rollup-plugin-buble')
const alias = require('rollup-plugin-alias')
const cjs = require('rollup-plugin-commonjs')
const replace = require('rollup-plugin-replace')
const node = require('rollup-plugin-node-resolve')
const flow = require('rollup-plugin-flow-no-whitespace')
const version = process.env.VERSION || require('../package.json').version
const weexVersion = process.env.WEEX_VERSION || require('../packages/weex-vue-framework/package.json').version

// 註釋內容,也就是程式碼上面對該程式碼的說明
const banner =
  '/*!\n' +
  ' * Vue.js v' + version + '\n' +
  ' * (c) 2014-' + new Date().getFullYear() + ' Evan You\n' +
  ' * Released under the MIT License.\n' +
  ' */'

const weexFactoryPlugin = {
  intro () {
    return 'module.exports = function weexFactory (exports, document) {'
  },
  outro () {
    return '}'
  }
}

// 引入./alias檔案
const aliases = require('./alias')
// 對resolve方法進行封裝,其實就是獲取檔案的路徑,如下面的entry入口檔案
const resolve = p => {
  const base = p.split('/')[0]
  if (aliases[base]) {
    return path.resolve(aliases[base], p.slice(base.length + 1))
  } else {
    return path.resolve(__dirname, '../', p)
  }
}

// 不同版本vue.js的配置
const builds = {
  // Runtime only (CommonJS). Used by bundlers e.g. Webpack & Browserify
  'web-runtime-cjs': {
    // 入口檔案,resolve函式呼叫aliases檔案,最終拼接該s檔案真正的路徑,如果aliases檔案中沒有定義,那麼就會走resolve函式的else
    entry: resolve('web/entry-runtime.js'),
    // 生成目標檔案
    dest: resolve('dist/vue.runtime.common.js'),
    // 構建出來的檔案的格式
    format: 'cjs',
    // 關於檔案的註釋
    banner
  },
  // 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-only production build (Browser)
  'web-runtime-prod': {
  },
  // Runtime+compiler development build (Browser)
  'web-full-dev': {
  },
  // Runtime+compiler production build  (Browser)
  'web-full-prod': {
  },
  // Web compiler (CommonJS).
  'web-compiler': {
  },
  // Web compiler (UMD for in-browser use).
  'web-compiler-browser': {
  },
  // Web server renderer (CommonJS).
  'web-server-renderer': {
  },
  'web-server-renderer-basic': {
  },
  'web-server-renderer-webpack-server-plugin': {
  },
  'web-server-renderer-webpack-client-plugin': {
  },
  // Weex runtime factory
  'weex-factory': {
  },
  // Weex runtime framework (CommonJS).
  'weex-framework': {
  },
  // Weex compiler (CommonJS). Used by Weex's Webpack loader.
  'weex-compiler': {
  }
}

// 構建工具rollup真正的配置,上面的是每一中版本的vue.js的配置,下面才是構建工具rollup真正的配置
function genConfig (name) {
  const opts = builds[name]
  const config = {
    input: opts.entry,
    external: opts.external,
    plugins: [
      replace({
        __WEEX__: !!opts.weex,
        __WEEX_VERSION__: weexVersion,
        __VERSION__: version
      }),
      flow(),
      buble(),
      alias(Object.assign({}, aliases, opts.alias))
    ].concat(opts.plugins || []),
    output: {
      file: opts.dest,
      format: opts.format,
      banner: opts.banner,
      name: opts.moduleName || 'Vue'
    }
  }

  if (opts.env) {
    config.plugins.push(replace({
      'process.env.NODE_ENV': JSON.stringify(opts.env)
    }))
  }

  Object.defineProperty(config, '_name', {
    enumerable: false,
    value: name
  })

  return config
}

if (process.env.TARGET) {
  module.exports = genConfig(process.env.TARGET)
} else {
  exports.getBuild = genConfig
  exports.getAllBuilds = () => Object.keys(builds).map(genConfig)
}

3.scripts檔案下alias.js

真實路徑的對映,
例如 config.js 中的builds物件

 entry: resolve('web/entry-runtime.js'),

web指的就是alias.js中 的

  web: resolve('src/platforms/web'),

完整程式碼

const path = require('path')

const resolve = p => path.resolve(__dirname, '../', p)
// 其實就是真實路徑的對映
module.exports = {
  vue: resolve('src/platforms/web/entry-runtime-with-compiler'),
  compiler: resolve('src/compiler'),
  core: resolve('src/core'),
  shared: resolve('src/shared'),
  web: resolve('src/platforms/web'),
  weex: resolve('src/platforms/weex'),
  server: resolve('src/server'),
  entries: resolve('src/entries'),
  sfc: resolve('src/sfc')
}

3.完整過程

npm run build

執行
script/build.js

build.js————-引入config.js,將配置進行過濾,過濾後再通過build函式進行真正的構建過程

config.js————引入alias.js,配置不同vue.js的配置,根據不同vue.js的配置輸出不同構建工具rollup真正的配置

alias.js————–提供檔案的路徑對映

相關推薦

vue2.x原始碼解析——原始碼構建

1.Rollup介紹 1.2rollup和webpack都是區別 webpack更加強大 可以將圖片,css等都解析為js。 rollup 更適合於js庫的編譯,只適用於js部分,別的檔案是不管的,並且更加友好 2.Vue.js 原始碼構建指令碼

Elastic-Job原始碼解析()之分片定時任務執行

通過本篇的閱讀你將學會了解Elastic-Job的定時時機,及如何通過分片方式做一個分散式的定時任務框架。瞭解常用的三種分片策略,及如何自定義分散式分片策略 目錄 Elastic-Job如何通過SpringJobScheduler啟動定時 Ela

spring cloud Config原始碼解析()

    前面說完我們如何從github上面去取資料,這裡說說server端剩餘的類。ConfigServerEncryptionConfiguration類。從類的名字我們可以看出主要是加解密相關的配置類,進入類中可以看到定義了EncryptionController encry

iOS總結-網路框架-AFNetworking原始碼解析()

參考https://www.jianshu.com/p/f32bd79233da 有關解析的主要是AFHTTPResponseSerializer: NSObject,其他的都是繼承AFHTTPResponseSerializer AFURLResponseSerialization的協議方

ReactiveSwift原始碼解析() Signal程式碼的基本實現

上篇部落格我們詳細的聊了ReactiveSwift原始碼中的Bag容器,詳情請參見《》。本篇部落格我們就來聊一下訊號量,也就是Signal的的幾種狀態以及Signal的基本實現。當然本篇部落格所解析的原始碼會用到上篇部落格介紹的Bag容器。本篇部落格我們先通過一個示例來看一下Signal是如何工作的,具體說來

RxDownload2 原始碼解析()

原始碼解析,如需轉載,請註明作者:Yuloran (t.cn/EGU6c76) 前言 造輪子者:Season_zlc 本文主要講述 RxDownload2 的多執行緒斷點下載技術 斷點下載技術前提 伺服器必須支援按 byte-range 下載,也就是支援 Range: bytes=xxx-

Mybatis 原始碼解析、Mapper介面與mapper.xml檔案繫結

     一、流程圖介紹整體過程               1、首先根據MapperScannerConfigurer進行包掃描,掃描Mapper介面,生成Spring特定的描述,並將其交

【進階】RecyclerView原始碼解析()——深度解析快取機制

上一篇部落格從原始碼角度分析了RecyclerView讀取快取的步驟,讓我們對於RecyclerView的快取有了一個初步的理解,但對於RecyclerView的快取的原理還是不能理解。本篇部落格將從實際專案角度來理解RecyclerView的快取原理。

aop原始碼解析-postProcessAfterInitialization

在aop原始碼解析二:postProcessBeforeInstantiation博文中 我們花了很長的一個篇幅介紹一個方法shouldSkip方法 雖然看名字很簡單 但裡面確實做了很多的事情 雖然最終也是沒有去建立代理 但這些工作並不是白做的 解析完以後快取起

java執行緒池(ThreadPoolExecutor)原始碼解析

ctl成員變數 /** * ctl 儲存了兩部分資訊 * workerCount : 執行緒數 * runStatus: 執行緒池的狀態 * * ctl 是一個 AtomicI

Mybatis 原始碼解析()

文章個人學習原始碼所得,若存在不足或者錯誤之處,請大家指出。 Properties配置格式如下: Configuration.xml中: <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE

mybatis原始碼解析()-SqlSession.selectOne類似方法呼叫過程

上篇部落格中介紹了mybatis的載入過程,這篇部落格介紹一下org.apache.ibatis.session.SqlSession的增、刪、改、查方法是怎麼實現的。我們使用mybatis時,基本都是使用Mapper進行增、刪、改、查操作,但是SqlS

分散式任務排程平臺XXL-JOB--原始碼解析:xxl-job-admin排程中心原始碼解析之初始化兩個Thread工作執行緒

 xxl-job-admin初始化工作 1.1 啟動時, 載入applicationcontext-xxl-job-admin.xml, 初始化spring容器 <!-- 這個排程中心,在啟動的時候,會做很多初始化的工作 ,比如:執行器資訊,註冊機器列表等資訊 --

Android原始碼解析-Android的構建過程(一)

1、aapt(Android Asset Packaging Tool)工具會將資原始檔進行轉化,生成對應資源ID的R檔案和資原始檔,比如Androidmanifest.xml,Layout中xml檔案等編譯為二進位制形式,assets資料夾中、raw資料夾

Vue2.x 響應式部分原始碼閱讀記錄

之前也用了一段時間Vue,對其用法也較為熟練了,但是對各種用法和各種api使用都是隻知其然而不知其所以然。最近利用空閒時間嘗試的去看看Vue的原始碼,以便更瞭解其具體原理實現,跟著學習學習。 ## Proxy 對 data 代理 ## 傳的 data 進去的為什麼可以用this.xxx訪問,而不

Curator原始碼解析(一)原始碼結構和測試程式

Curator是Netflix開源的一套ZooKeeper客戶端框架. Netflix在使用ZooKeeper的過程中發現ZooKeeper自帶的客戶端太底層, 應用方在使用的時候需要自己處理很多事情, 於是在它的基礎上包裝了一下, 提供了一套更好用的客戶端框架. Net

2048小遊戲(Java)原始碼解析原始碼打包

資料結構課程設計寫的2048小遊戲,答辯完了就開源了,因為這次的技術文件任性地寫成了傻瓜式教程了,就乾脆也放出來了,供參考,原始碼打包在最後面會附上。 一、 實現方案 本遊戲採用Java語言編寫,使用Eclipse編譯器, jdk1.7.0_51編

Java原始碼解析|String原始碼與常用方法

String原始碼與常用方法 1.栗子 程式碼: public class JavaStringClass { public static void main(String[] args) { String s ="hello"; s =

RxJava 2.x 教程及原始碼揭祕()Rxjava操作符原始碼解析

本文將探究: 知道執行緒排程是怎麼實現的 知道操作符是怎麼實現的 RxJava最強大的莫過於它的執行緒排程 和 花式操作符。 map操作符 map是一個高頻的操作符,我們首先拿他開刀。 例子如下,源頭Observable傳送的是String型別的數字,利用map轉換成

vue2.x原始碼解析準備--對原始碼進行debugger

1.debugger原始碼 我們學習vue原始碼採用的是Runtime+Compiler的版本 當我們vue-cli建立完成後 build/webpack.base.conf.js中 resolve: { extensions: ['.js'