The introduction

Recently, the project needs to provide a packaged JS SDK. Although it is a very simple function at present, webPack is still selected as a packaging tool for future maintenance and expansion. As a reference, I recommend a good article, interested friends can read it first

JavaScript SDK Design Guide

The target

As an SDK, I wanted to do the following

  • Provide a loading scheme
  • Expose a common variable, preferably one that supports multiple loading methods
  • Uncompressed and compressed versions are available
  • Customized versions can be provided for different partners
  • Internal implementations are referenced by modules for easy extension

How do you do that with WebPack

To prepare

Let’s say the SDK we finally need to provide is as follows

/ / reference < scripttype="text/javascript" src="http://xxx.com/sdk.js"></script> // Use window.sdk.shop.getList () // to get the Store information list window.sdk.store.getbyId () // to get the product information by IDCopy the code

The list of files should look something like this

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

Webpack packages the files through the index.js entry and places them in the dist folder. The code for some key files should be as follows

webpack.config.js

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

module.exports = {
    entry: {
        'sdk': ['./src/index.js']
    },
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: '[name].js'} / / compression confuse js plugins: [new webpack. Optimize. UglifyJsPlugin ({compress: {warnings:false
            },
            sourceMap: true}})]Copy the code

shop.js

module.exports = {
    getList: function() {... }}Copy the code

store.js

module.exports = {
    getById: function(id) { ..... }}Copy the code

index.js

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

module.exports = {
    Shop: Shop,
    Store: Store
}
Copy the code

build.js

// Simply copy the build code provided by vue-CLIlet 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)
})

Copy the code

plan

1. Load a reference

This part is easy to implement

  • Provide a static file address (or a CDN address) for easy HTML loading
  • Provide an NPM package and load it on the server side (suspend it because there is no need for this yet)

2. Expose a public variable

The easiest way to do this is to add a line window.sdk =… to index.js.

But Webpack has a better solution, output.library

The output option is mainly used to configure file output rules, while the output.library option can be used to expose the file as a variable when it is output, so to speak, a configuration item built to package SDK files

There is also a Webpack tutorial to help you create a Library using Library

The other option, output.libraryTarget, sets how to output variables. The default value is var

Just a quick explanation of what these values mean

  • Var: Exports a variable in the current scope
  • Assign: Exports a variable as a global variable
  • This: Export asthisA property of theta, this onethisIs not necessarilywindowDepending on where the SDK is referenced
  • Window: Export aswindowIs basically a global variable
  • Global: The value is exported asglobalIs a property of the variable name.
  • Commonjs: Exported asexportsA property of the export format can be inCommonJSContext reference
  • Commonjs2: Assigns tomodule.exportsCan also be used inCommonJSIn the environment
  • Amd: Exposed to AMD modules
  • Umd: Exposed as a format available to all modules
  • Jsonp: wrapped in a JSONP wrapper, that is, a Function

So let’s modify the webpack.config.js code a little bit

module.exports = {
    ...
    output: {
        path: './dist',
        filename: '[name].js',
        library: 'SDK',
        libraryTarget: "umd"}... }Copy the code

3. Provide two versions

It is easy to write two build scripts, packaged as compressed and uncompressed code, but WebPack itself can also be exported to multiple configurations (see how WebPack can configure different parameters for multiple outputs).

So, our webpack.config.js code is changed to

Module. exports = [// uncompressed {entry: {'sdk': './src/index.js'
        },
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: '[name].js',
            library: 'SDK',
            libraryTarget: "umd"}}, // Compressed version {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}})]]Copy the code

The packaged result is shown below

4. Provide customized versions

This is relatively easy, you can do multiple configurations through the previous way, or you can simply write multiple entries in the entry

Change the webpack.config.js code to

module.exports = [
    {
        entry: {
            'sdk': './src/index.js'.'custom': './src/custom.js'}... },... ]Copy the code

5. Internal implementations are referenced by modules

This is no longer wordy… After a number of configurations, ES6 can add modules, but note that if you introduce Babel or other libraries, the packaged SDK files will be very large. Even a simple reference to a Webpack-Merge will add 50K of capacity. Therefore, it is better to write it in the native way. If you need Ajax and other functions, you can simply wrap it and do not reference other libraries if possible. If you feel that the file size is too large, you can use Webpack-bundle-Analyzer to analyze the distribution of file size and whether there are duplicate references

conclusion

Although is a small project, but also should be considered in the early of comprehensive, current projects are small, but not necessarily will develop into what kind, there may be some people will say that such a simple project encapsulated with closures, exposed two interfaces can, why do so complicated, but if need to add a new interface, if need to provide two SDK, If you provide different interfaces and have some of the same interfaces at the same time, will it have a big impact on the online network? How much testing is required? This creates a lot of cost and uncertainty for us

I hope this initial article will help you in creating an SDK project