When you create a npm package, remember it might be used in a browser or a server, or even a command line utility… For each package you create, please pay attention at what it will be used for:
- Is it going to be used as a dependency to a nodejs application that is not bundled? (e.g. command line utilities)
- Is it going to be used as a dependency to a nodejs application that is bundled? (e.g. AWS Lambdas)
- Is it going to be used as a dependency to a browser application (always bundled)?.
- In cases 2) and 3) you want to allow for tree shaking.
- In cases 1) and 2) you want to benefit from the "ES6"/"ES next" features supported natively by nodejs.
- In case 3) you also want to benefit from the native support of "ES6" from your browser.
Note: The examples below will assume that you do not care about people using old browsers or a version of nodejs prior to 6.10.
For a package that might be used as a dependency to a nodejs application that is not bundled...
-
You need to compile your code to the folder
./dist
. -
You need to define the following entry point in
package.json
:"main": "./dist/index.js"
. -
And you need to use the preset below.
"presets": [ ["babel-preset-env", { "targets": { "node": "6.10" } }] ]
For a package that might be used as a dependency to a nodejs application that is bundled...
-
You need to compile your code to the folder
./module
. -
You need to define the following entry point in
package.json
:"module": "./module/index.js"
. -
And you need to use the preset below.
"presets": [ ["babel-preset-env", { "targets": { "node": "6.10" }, "modules": false }] ]
For a package that might be used as a dependency to a browser application that would obviously be bundled...
-
You need to compile your code to the folder
./lib
. -
You need to define the following entry point in
package.json
:"browser": "./lib/index.js"
. -
And you need to use the preset below.
"presets": [ ["babel-preset-env", { "targets": { "browsers": "last 2 versions, ie 10-11" }, "modules": false }] ]
This is an example of how the .babelrc
file might look like for an npm package that might be used in any application.
{
"env": {
"development": {
"presets": [
["babel-preset-env", {
"targets": {
"node": "6.10"
}
}]
],
"plugins": [
"transform-object-rest-spread",
"transform-class-properties",
...
]
},
"browser": {
"presets": [
["babel-preset-env", {
"targets": {
"browsers": "last 2 versions, ie 10-11"
},
"modules": false
}]
],
"plugins": [
"transform-object-rest-spread",
"transform-class-properties",
...
]
},
"module": {
"presets": [
["babel-preset-env", {
"targets": {
"node": "6.10"
},
"modules": false
}]
],
"plugins": [
"transform-object-rest-spread",
"transform-class-properties",
...
]
}
},
"sourceMaps": true
}
This is an example of how the package.json
file might look like for an npm package that might be used in any application.
{
...
"main": "./dist/index.js",
"browser": "./lib/index.js",
"module": "./module/index.js",
"scripts": {
...
"build-browser": "cross-env BABEL_ENV=browser babel ./src --out-dir ./lib --source-maps --copy-files",
"build-module": "cross-env BABEL_ENV=module babel ./src --out-dir ./module --source-maps --copy-files",
"build-node": "babel ./src --out-dir ./dist --source-maps --copy-files",
"build ": "npm run build-node && npm run build-browser && npm run build-module"
},
...
}
Finally in the consuming application, you should configure webpack.config.js
as followed. If the application runs in the browser, use the following. (Obviously this file would also need to contain configuration for CSS, etc.)
Note that webpack will assume target: 'web'
. This is what tells webpack that this bundle is expected to be used in the browser. And webpack will automatically look for the entry point browser
rather than main
in each dependency.
const webpack = require('webpack');
...
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: {
...
},
output: {
filename: '[name].js',
path: ...
},
...,
module: {
rules: [
...
]
},
plugins: [
...,
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new UglifyJSPlugin({
uglifyOptions: {
beautify: false,
ecma: 6,
compress: true,
comments: false
}
}),
…
]
};
If the application runs on a server, use the following. Note the property target: 'node'
. This is what tells webpack that this bundle is expected to be used on the server rather than the browser. And webpack will automatically look for the entry point module
rather than main
in each dependency.
const webpack = require('webpack');
...
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
target: 'node',
entry: {
app: …
},
output: {
filename: '[name].js',
path: ...,
library: '???',
libraryTarget: 'commonjs'
},
...,
plugins: [
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new UglifyJSPlugin({
uglifyOptions: {
beautify: false,
ecma: 6,
compress: true,
comments: false
}
}),
...
]
};