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 as
this
A property of theta, this onethis
Is not necessarilywindow
Depending on where the SDK is referenced- Window: Export as
window
Is basically a global variable- Global: The value is exported as
global
Is a property of the variable name.- Commonjs: Exported as
exports
A property of the export format can be inCommonJSContext reference- Commonjs2: Assigns to
module.exports
Can 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