用 webpack 寫一個簡單的 JS SDK

引言

最近項目中須要提供一個封裝的JS SDK,雖然目前是一個很簡單的功能,可是爲了往後便於維護,擴展,所以仍是選用了 webpack 做爲打包工具,做爲參考,推薦一篇上好的文章,感興趣的朋友能夠先閱讀一下javascript

JavaScript SDK Design Guide (中文翻譯: JavaScript SDK設計指南html

目標

做爲一個SDK,我想達到以下的目的vue

  • 提供一個加載方案
  • 暴露一個公共變量,最好能支持多種加載方式
  • 提供未壓縮版與壓縮版
  • 能夠爲不一樣的合做商提供定製版本
  • 內部實現經過模塊引用,方便擴展

接下來一步步講一下如何經過 webpack 實現java

準備

假如咱們最後須要提供的 SDK 以下node

// 引用
<script type="text/javascript" src="http://xxx.com/sdk.js"></script>

// 使用
window.SDK.Shop.getList()       // 獲取門店信息列表
window.SDK.Store.getById()      // 經過ID獲取商品信息
複製代碼

那麼文件列表應該大體以下webpack

|
| - package.json
| - webpack.config.js
| - node_modules
| - src
    | - index.js
    | - lib
        | - shop.js
        | - store.js
| - dist
| - build.js

複製代碼

webpack 經過 index.js 入口打包好文件,放到 dist 文件夾,一些關鍵文件的代碼應該以下git

webpack.config.jsgithub

let path = require('path')
let webpack = require('webpack')

module.exports = {
    entry: {
        'sdk': ['./src/index.js']
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'
    }, 
    // 壓縮混淆 js
    plugins: [
        new webpack.optimize.UglifyJsPlugin({
            compress: {
                warnings: false
            },
            sourceMap: true
        })
    ]
}
複製代碼

shop.jsweb

module.exports = {
    getList: function () {
        .....
    }
}
複製代碼

store.jsajax

module.exports = {
    getById: function (id) {
        .....
    }
}
複製代碼

index.js

var Shop = require('./lib/shop.js')
var Store = require('./lib/store.js')

module.exports = {
    Shop: Shop,
    Store: Store
}
複製代碼

build.js

// 這裏簡單的 copy 了 vue-cli 提供的 build 代碼
let webpackConfig = require('./webpack.config')

let rm = require('rimraf')
let path = require('path')
let webpack = require('webpack')
let util = require('util')

const compileCallback = (er, stats) => {
    if (er) throw er
    stats = util.isArray(stats.stats) ? stats.stats : [stats]
    stats.forEach((item) => {
        process.stdout.write(item.toString({
            colors: true,
            modules: false,
            children: false,
            chunks: false,
            chunkModules: false
        }) + '\n\n')
    })         

    console.log('Build complete.\n')
}

rm(path.resolve(__dirname, './dist'), err => {
    if (err) throw err
    let compiler = webpack(webpackConfig)
    
    compiler.run(compileCallback)
})

複製代碼

方案

1. 加載引用

這部分很好實現

  • 提供一個靜態文件地址(或者一個CDN地址)來簡單的經過 html 加載
  • 提供一個npm包,在服務器端加載(由於暫時沒這種需求,因此先掛起)

2. 暴露一個公共變量

最簡單的作法是在 index.js 里加一句 window.SDK = ...

不過 webpack 有更好的解決方案 output.library

output 選項主要用於配置文件輸出規則,而 output.library 選項能夠用於輸出時將文件暴露爲一個變量,能夠說是爲了打包 SDK 文件而生的一個配置項

這裏還有一個 webpack 的教程來幫你如何使用 library 建立 Library

另外一個選項 output.libraryTarget 則能夠配置如何輸出變量,默認值是 var

簡單的說明一下這些值的含義

  • var:在當前做用域導出一個變量
  • assign: 導出一個變量做爲全局變量
  • this: 導出做爲 this 的一個屬性,這個 this 不必定是 window ,要看引用 SDK 的位置
  • window: 導出爲 window 的一個屬性,基本上就算全局變量了
  • global:導出爲 global 的一個屬性,估計是這個變量名比較經常使用吧。。
  • commonjs:導出爲 exports 的一個屬性,導出的格式能夠在 CommonJS 環境裏引用
  • commonjs2:賦值給 module.exports ,一樣能夠用在 CommonJS 環境裏
  • amd:暴露給 AMD 模塊
  • umd:暴露爲全部模塊均可用的格式
  • jsonp:包裹到一個 jsonp 包裝容器中,也就是一個 Function

所以,咱們稍微修改一下 webpack.config.js 的代碼

module.exports = {
    ...
    output: {
        path: './dist',
        filename: '[name].js',
        library: 'SDK',
        libraryTarget: "umd"
    }
    ...
}
複製代碼

3. 提供兩個版本

簡單的能夠寫兩個 build 腳本,分別打包爲壓縮代碼與未壓縮代碼,不過 webpack 自己也能夠導出爲多個配置(這也摸清了 webpack 如何爲多個 output 配置不一樣的參數)

因而,咱們的 webpack.config.js 代碼修改成

module.exports = [
  // 未壓縮版
  {
        entry: {
            'sdk': './src/index.js'
        },
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: '[name].js',
            library: 'SDK',
            libraryTarget: "umd"
        }
  },

  // 壓縮版
  {
        entry: {
            'sdk.min': './src/index.js'
        },
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: '[name].js',
            library: 'SDK',
            libraryTarget: "umd"
        },
        plugins: [
            new webpack.optimize.UglifyJsPlugin({
                compress: {
                    warnings: false
                },
                sourceMap: true
            })
        ]
  }
]
複製代碼

打包後的結果以下圖所示

4. 提供定製版本

這個相對容易點了,能夠經過上一條的方式作多個配置,也能夠簡單的在 entry 中寫多個入口

webpack.config.js 代碼修改成

module.exports = [
    {
        entry: {
            'sdk': './src/index.js',
            'custom': './src/custom.js'
        }
        ...
    },
    ...
]
複製代碼

5. 內部實現經過模塊引用

這個就再也不囉嗦了...通過了一系列配置,別說模塊了,ES6都能給你加進去,不過要注意的是,若是引入了 babel 或者其餘的庫,打包出來的 SDK 文件就很大了,甚至是簡單的引用一個 webpack-merge 都會增長50K的容量,因此最好仍是以原生的方式去寫,若是須要 ajax 等功能就簡單的封裝一下,能不引用別的庫就不引用,若是以爲文件體積太大,能夠用 webpack-bundle-analyzer 分析一下文件大小的分佈,以及是否有重複引用

結語

雖然是個小項目,不過在初期也應該考慮的全面,目前項目雖小,可是不見得之後會發展成什麼樣,可能有些人會說這麼簡單的項目用閉包封裝一下,暴露兩個接口便可,何須搞那麼複雜,可是假如以後須要添加新的接口呢,假如須要提供兩個 sdk ,分別提供不一樣的接口,同時又有部分相同的接口呢,若是這時候再進行重構,會不會對線上有很大的影響?須要進行多少測試?這無形之中給咱們加大了不少成本與不肯定性

但願這篇比較初級的文章能對你們在建立一個SDK項目上有所幫助~

相關文章
相關標籤/搜索