【構建】定製SDK打包工具(gulp版本)

如今流行 mvvm 三大框架,各類cli 工具也給咱們提供了不少方便。我在工做中使用的是vue 技術棧。vue-cli 讓我不能更爽了。分分鐘拉起架子,開始各類業務代碼。javascript

可是,工做中我還遇到另外一種狀況,就是我須要寫一些 SDK 文件,有對內的也有對外的。每次寫這個都讓我蛋疼的不要不要的,若是使用 cli ,須要依賴,文件太大不合適。若是手工去寫,好多es6的語法用不上,還得本身處理 polyfill。 索性根據須要本身搭建一套腳手架。css

需求

開始以前,咱們先分析下須要哪些功能。SDK 通常都是提供一些Api方法,其中絕大多數可能都是JS。因此咱們可能須要如下的一些能力。vue

  • ES6 轉義爲 ES5 語法
  • 有可能須要分模塊,須要處理 import
  • 壓縮

開始

webpackgulp 都是目前比較流行的構建工具。此次咱們使用 gulp 來構建。java

首先新建一個空的文件sdk-cli。而後執行如下命令,初始化一個package.json 文件。node

npm init -y
複製代碼

下一步,咱們全局和本地安裝gulp。webpack

npm install -g gulp
npm install gulp --save-dev
複製代碼

咱們在跟目錄下新建一個 ``gulpfile.jsgit

// gulpfile.js
const gulp = require('gulp');
複製代碼

同時,咱們在根目錄下建立一個app.js 文件。es6

// app.js 測試代碼
let SDK = {
    show: () =>{
        console.log('this is function')
    },
    init(options){
        let _opt = {
            name:'zhangsan',
            age: 23
        }
        options = Object.assign(_opt,options);
        console.log(options);
    }
}

window.SDK = SDK;
複製代碼

編譯ES6

下一步,咱們開始編譯上面的app.js 文件,最後輸出。github

編譯ES6,咱們就須要用到 gulp-babel 這個插件了。web

npm install gulp-babel --save-dev
複製代碼

同時,咱們須要建立一個 .babelrc 的文件,這個文件是定義了一些 babel 的規則。

// .babelrc
{
	"presets": [
		[
			"@babel/preset-env",
			{
				"useBuiltIns": "usage",  //根據代碼的須要加載polyfill
				"corejs": 3  // 依賴corejs-3
			}
		]
	]
}
複製代碼

主要是把es6的語法轉換爲es5的語法。

下面咱們往 gulpfile.js 中添加一些代碼。

const gulp = require('gulp');
const babel = require('gulp-babel');

function js(){
    return gulp.src('./app.js') // 輸入 app.js
        .pipe(babel())		// babel 轉換代碼 
        .pipe(gulp.dest('./dist/'))	  	// 輸出到dist文件夾下,會自動建立文件夾
}
exports.js = js; // 輸出task任務爲js
複製代碼

而後咱們執行構建代碼

gulp js
複製代碼

而後咱們會看到報錯

$ gulp js
internal/modules/cjs/loader.js:638
    throw err;
    ^

Error: Cannot find module '@babel/core'
    at Function.Module._resolveFilename (internal/modules/cjs/loader.js:636:15)
    at Function.Module._load (internal/modules/cjs/loader.js:562:25)
    at Module.require (internal/modules/cjs/loader.js:690:17)
    at require (internal/modules/cjs/helpers.js:25:18)
    at Object.<anonymous> (D:\hlmy\learning\sdk-clis\node_modules\gulp-babel\index.js:7:15)
    at Module._compile (internal/modules/cjs/loader.js:776:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
複製代碼

這是由於雖然咱們安裝了 gulp-babel ,他只是一個工具庫,他還須要用到 @babel/core 這個核心庫。一樣道理,也須要安裝@babel/preset-env

npm install @babel/core @babel/preset-env -D
複製代碼

安裝完以後,咱們在試着跑下命令

gulp js
複製代碼

咱們會看到此次成功了,在 dist 文件夾下輸出了一個 app.js文件。

他是長這樣的,

"use strict";

require("core-js/modules/es.object.assign");

// app.js 測試代碼
var SDK = {
  show: function show() {
    console.log('this is function');
  },
  init: function init(options) {
    var _opt = {
      name: 'zhangsan',
      age: 23
    };
    options = Object.assign(_opt, options);
    console.log(options);
  }
};
window.SDK = SDK;
複製代碼

跟咱們的源文件比一下,會發現他把一些es6的語法,好比 箭頭函數 , 對象寫法 轉換成了 es5的語法。

babel 轉換是分爲兩部分,一個是轉換語法,一個是轉換 api。默認狀況下直接轉換語法,api部分是經過polyfill來實現的。

例如: Object.assign 就是經過引入require("core-js/modules/es.object.assign"); 來解決。

這是由於,babel 默認是轉換成commonjs 格式的,這是啥意思呢,就是說他最終轉換成能在node 服務中使用。

若是咱們想要在瀏覽器中再次能使用,就得再次處理。好比下面這個插件。

browserify

npm install browserify vinyl-source-stream -D
複製代碼

咱們在改一下 gulpfile.js 文件

const gulp = require('gulp');
const babel = require('gulp-babel');
const browserify = require('browserify');
const source = require('vinyl-source-stream');

function js(){
    return gulp.src('./app.js') // 輸入 app.js
        .pipe(babel())		// babel 轉換代碼 
        .pipe(gulp.dest('./dist/'))	  	// 輸出到dist文件夾下,會自動建立文件夾
}

function browser(){
    var b = browserify({
        entries: "dist/app.js"
    });
    return b.bundle()
        // 將常規流轉換爲包含 Stream 的 vinyl 對象
        .pipe(source("bundle.js"))
        .pipe(gulp.dest("dist/"));
}

exports.js = js; // 輸出task任務爲js
exports.browser = browser;
複製代碼

此次咱們引入了兩個插件browserifyvinyl-source-stream

browserify 就是把 commonjs 格式轉換成 瀏覽器可用的文件。功能很強大,咱們這裏主要使用的是他的基本功能。

vinyl-source-stream 這個插件是把常規的數據流轉換成包含 Streamvinyl 對象。

數據流

咱們都知道 gulp 是流處理,可是它的流和 咱們一般所說的 node 的流不是一個東西。gulp的流是基於 vinyl , 這是一個虛擬對象格式。

咱們去 vinyl 的官網看下,他的用法是這樣的。

var Vinyl = require('vinyl');

var jsFile = new Vinyl({
  cwd: '/',
  base: '/test/',
  path: '/test/file.js',
  contents: new Buffer('var x = 123')
});
複製代碼

vinyl格式除了內容外,還包含一些路徑的信息。它的contents總共有三種格式,Stream Buffernull

而gulp 默認使用的是 包含 Buffervinyl 對象。

vinyl的做用

那爲何gulp 不使用普通的 node 的Stream流呢,而要本身弄一個 vinyl 虛擬格式呢?咱們看一下以下代碼:

function css(){
    gulp.src('./css/**/*.css')
    	.pipe(gulp.dest('./dist'))
}
exports.css = css;
複製代碼

這段代碼的意思是,把css目錄下的全部css文件,複製到dist目錄下。

請注意這個包含多級目錄,咱們知道gulp會自動建立沒有的目錄和文件名。而node 的stream 流呢,他只傳輸Stream Buffer這些,不關心路徑的問題。因此就須要使用 vinyl 格式。

其實 vinyl 虛擬格式是一個對普通流的包裝。

安裝core-js

言歸正傳,咱們接着寫構建。若是你如今去運行構建命令 gulp browser,是會報錯的。爲何呢,由於咱們還須要安裝core-js 。gulp 的 polyfill 都是經過這個庫包含的,因此咱們須要安裝。

npm install core-js -D
複製代碼

而後咱們在運行一下

gulp browser
複製代碼

咱們打開 dist看一下,下面有兩個文件app.jsbundle.js

bundle.js 使咱們最終所須要的文件。

掃尾工做

主要轉換工做,已經作完。剩下咱們還須要一些掃尾工做,好比 壓縮

上面是兩步操做,因此咱們也須要合併,刪除一些中間文件。

最終以下:

// gulpfile.js

const gulp = require('gulp');
// 編譯es6
const babel = require('gulp-babel');
// 編譯commonjs
const browserify = require('browserify');
// 轉換爲stream的vinyl對象
const source = require('vinyl-source-stream');
// 轉換爲buffer的vinyl對象
const buffer = require('vinyl-buffer');
// 壓縮
const uglify = require("gulp-uglify");
// 清除文件
const clean = require('gulp-clean');

function js(){
    return gulp.src('./app.js') // 輸入 app.js
        .pipe(babel())		// babel 轉換代碼 
        .pipe(gulp.dest('./dist/'))	  	// 輸出到dist文件夾下,會自動建立文件夾
}

function browser(){
    var b = browserify({
        entries: "dist/app.js"
    });
    return b.bundle()
        // 將常規流轉換爲包含 Stream 的 vinyl 對象
        .pipe(source("bundle.js"))
        // 將 vinyl 對象內容中的 Stream 轉換爲 Buffer
        .pipe(buffer())
        // 壓縮
        .pipe(uglify())
        .pipe(gulp.dest("dist/"));
}

// 刪除中間文件
async function del(){
    await gulp.src('./dist/app.js')
        .pipe(clean())
}

exports.js = js; // 輸出task任務爲js
exports.browser = browser;
// 順序執行task
exports.es = gulp.series( js,browser,del)

複製代碼

差很少到如今爲止,一個簡單的構建就出來了。可用知足使用了。

另外,gulpbabel browserify 都是很靈活的。因此以上的用法只是其中的一個,你們若是有興趣也能夠嘗試用其餘的一些插件來完成。總體思路是這樣。

若是你們對 構建工具開發SDK,有什麼好的方法或者新的。能夠留言一塊兒探討。

全部的代碼在 github上,有須要能夠本身查看。

參考連接:

segmentfault.com/a/119000000…

zhuanlan.zhihu.com/p/58624930

github.com/browserify/…

gulpjs.com/docs/en/get…

www.babeljs.cn/docs/

相關文章
相關標籤/搜索