diff --git a/BUILDING.md b/BUILDING.md index 639809c394a..816ecb20daa 100644 --- a/BUILDING.md +++ b/BUILDING.md @@ -1,5 +1,7 @@ # Building plotly.js +The easiest way to bundle plotly.js into your application is to use one of the distributed plotly.js packages on npm. These distributed packages should just work with **any** build framework. That said, if you're looking to save a few bytes, read the section below corresponding to your building framework. + ## Webpack For plotly.js to build with Webpack you will need to install [ify-loader@v1.1.0+](https://github.com/hughsk/ify-loader) and add it to your `webpack.config.json`. This adds Browserify transform compatibility to Webpack which is necessary for some plotly.js dependencies. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4c637c3924e..ff76c5dc699 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -208,7 +208,7 @@ This will produce the following plot, and say you want to simulate a selection p - All tasks can be run using [`npm run-script`](https://docs.npmjs.com/cli/run-script) - Tests are `test/`, they are partitioned into `image` and `jasmine` tests - Test dashboard and image viewer code is in `devtools/` -- Non-distributed, built files are in `build/` (most files in here are git-ignored, the css and font built files are exceptions) +- Built files are in `build/` (most files in here are git-ignored, the css and font built files are exceptions) ## Coding style diff --git a/README.md b/README.md index f1b1e83fe03..8b2416c21c9 100644 --- a/README.md +++ b/README.md @@ -32,28 +32,16 @@ and more. ## Quick start options -#### Download the latest release -[Latest Release on Github](https://github.com/plotly/plotly.js/releases/) - -and use the plotly.js `dist` file(s). More info [here](https://github.com/plotly/plotly.js/blob/master/dist/README.md). - -#### Clone the repo +### Install with npm ```bash -git clone https://github.com/plotly/plotly.js.git +npm install plotly.js-dist ``` -and use the plotly.js `dist` file(s). - -#### Install with `npm` - -```bash -npm install plotly.js -``` +and import plotly.js as `import Plotly from 'plotly.js-dist';` or `var Plotly = require('plotly.js-dist');`. -and require plotly.js using CommonJS as `var Plotly = require('plotly.js');` or use the plotly.js `dist` file(s). +### Use the plotly.js CDN hosted by Fastly -#### Use the plotly.js CDN hosted by Fastly ```html @@ -62,18 +50,27 @@ and require plotly.js using CommonJS as `var Plotly = require('plotly.js');` or - + ``` and use the `Plotly` object in the window scope. -##### Read the [Getting started page](https://plot.ly/javascript/getting-started/) for more examples. +### Download the latest release + +[Latest Release on Github](https://github.com/plotly/plotly.js/releases/) + +and use the plotly.js `dist` file(s). More info [here](https://github.com/plotly/plotly.js/blob/master/dist/README.md). + +#### Read the [Getting started page](https://plot.ly/javascript/getting-started/) for more examples. + ## Modules -Starting in `v1.15.0`, plotly.js also ships with several _partial_ bundles (more info [here](https://github.com/plotly/plotly.js/blob/master/dist/README.md#partial-bundles)). +Starting in `v1.15.0`, plotly.js ships with several _partial_ bundles (more info [here](https://github.com/plotly/plotly.js/blob/master/dist/README.md#partial-bundles)). + +Starting in `v1.39.0`, plotly.js publishes _distributed_ npm packages with no dependencies. For example, run `npm install plotly.js-geo-dist` and add `import Plotly from 'plotly.js-geo-dist';` to your code to start using the plotly.js geo package. -If you would like to manually pick which plotly.js modules to include, you can create a *custom* bundle by using `plotly.js/lib/core`, and loading only the trace types that you need (e.g. `pie` or `choropleth`). The recommended way to do this is by creating a *bundling file*: +If none of the distributed npm packages meet your needs, and you would like to manually pick which plotly.js modules to include, you'll first need to run `npm install plotly.js` and then create a *custom* bundle by using `plotly.js/lib/core`, and loading only the trace types that you need (e.g. `pie` or `choropleth`). The recommended way to do this is by creating a *bundling file*. For example, in CommonJS: ```javascript // in custom-plotly.js diff --git a/package.json b/package.json index 733c9e01b1f..1e7f6df86f8 100644 --- a/package.json +++ b/package.json @@ -46,7 +46,8 @@ "baseline": "node tasks/baseline.js", "preversion": "check-node-version --node 8 --npm 5 && npm-link-check && npm ls --prod", "version": "npm run build && git add -A dist src build", - "postversion": "node -e \"console.log('Version bumped and committed. If ok, run: git push && git push --tags')\"" + "postversion": "node -e \"console.log('Version bumped and committed. If ok, run: git push && git push --tags')\"", + "postpublish": "node tasks/sync_package.js" }, "browserify": { "transform": [ diff --git a/tasks/stats.js b/tasks/stats.js index dd7fdb0c972..da597ce71b9 100644 --- a/tasks/stats.js +++ b/tasks/stats.js @@ -1,7 +1,6 @@ var path = require('path'); var fs = require('fs'); -var falafel = require('falafel'); var gzipSize = require('gzip-size'); var prettySize = require('prettysize'); @@ -11,7 +10,6 @@ var pkg = require('../package.json'); var pathDistREADME = path.join(constants.pathToDist, 'README.md'); var cdnRoot = 'https://cdn.plot.ly/plotly-'; -var coreModules = ['scatter']; var ENC = 'utf-8'; var JS = '.js'; @@ -110,6 +108,7 @@ function getMainBundleInfo() { '- using CDN URL ' + cdnRoot + 'latest' + MINJS + ' OR ' + cdnRoot + pkg.version + MINJS, '', 'or as raw javascript:', + '- using the `plotly.js-dist` npm package (starting in `v1.39.0`)', '- using dist file `dist/plotly.js`', '- using CDN URL ' + cdnRoot + 'latest' + JS + ' OR ' + cdnRoot + pkg.version + JS, '- using CommonJS with `require(\'plotly.js\')`', @@ -129,7 +128,8 @@ function getMainBundleInfo() { 'Starting in `v1.15.0`, plotly.js also ships with several _partial_ bundles:', '', constants.partialBundlePaths.map(makeBundleHeaderInfo).join('\n'), - '' + '', + 'Starting in `v1.39.0`, each plotly.js partial bundle has a corresponding npm package with no dependencies.' ]; } @@ -156,26 +156,55 @@ function makeBundleHeaderInfo(pathObj) { function makeBundleInfo(pathObj) { var name = pathObj.name; var sizes = findSizes(pathObj); - var moduleList = coreModules.concat(scrapeContent(pathObj)); + var moduleList = common.findModuleList(pathObj.index); + var pkgName = 'plotly.js-' + name + '-dist'; return [ '### plotly.js ' + name, '', - formatBundleInfo(name, moduleList), + 'The `' + name + '` partial bundle contains trace modules ' + common.formatEnumeration(moduleList) + '.', + '', + '#### Stats', + '', + '| Raw size | Minified size | Minified + gzip size |', + '|------|-----------------|------------------------|', + '| ' + sizes.raw + ' | ' + sizes.minified + ' | ' + sizes.gzipped + ' |', + '', + '#### CDN links', + '', + '| Flavor | URL |', + '| ------ | --- |', + '| Latest | ' + cdnRoot + name + '-latest' + JS + ' |', + '| Latest minified | ' + cdnRoot + name + '-latest' + MINJS + ' |', + '| Tagged | ' + cdnRoot + name + '-' + pkg.version + JS + ' |', + '| Tagged minified | ' + cdnRoot + name + '-' + pkg.version + MINJS + ' |', + '', + '#### npm package (starting in `v1.39.0`)', + '', + 'Install [`' + pkgName + '`](https://www.npmjs.com/package/' + pkgName + ') with', + '```', + 'npm install ' + pkgName, + '```', + '', + 'ES6 module usage:', + '```js', + 'import Plotly from \'' + pkgName + '\'', + '```', + '', + 'CommonJS usage:', + '```js', + 'var Plotly = require(\'' + pkgName + '\');', + '```', '', - '| Way to import | Location |', + '#### Other plotly.js entry points', + '', + '| Flavor | Location |', '|---------------|----------|', '| dist bundle | ' + '`dist/plotly-' + name + JS + '` |', '| dist bundle (minified) | ' + '`dist/plotly-' + name + MINJS + '` |', - '| CDN URL (latest) | ' + cdnRoot + name + '-latest' + JS + ' |', - '| CDN URL (latest minified) | ' + cdnRoot + name + '-latest' + MINJS + ' |', - '| CDN URL (tagged) | ' + cdnRoot + name + '-' + pkg.version + JS + ' |', - '| CDN URL (tagged minified) | ' + cdnRoot + name + '-' + pkg.version + MINJS + ' |', + '| ES6 module | ' + '`import Plotly from \'plotly.js/lib/' + 'index-' + name + '\'`' + ' |', '| CommonJS | ' + '`require(\'plotly.js/lib/' + 'index-' + name + '\')`' + ' |', '', - '| Raw size | Minified size | Minified + gzip size |', - '|------|-----------------|------------------------|', - '| ' + sizes.raw + ' | ' + sizes.minified + ' | ' + sizes.gzipped + ' |', '' ].join('\n'); } @@ -197,50 +226,3 @@ function findSizes(pathObj) { return sizes; } - -function scrapeContent(pathObj) { - var code = fs.readFileSync(pathObj.index, ENC); - var moduleList = []; - - falafel(code, function(node) { - if(isModuleNode(node)) { - var moduleName = node.value.replace('./', ''); - moduleList.push(moduleName); - } - }); - - return moduleList; -} - -function isModuleNode(node) { - return ( - node.type === 'Literal' && - node.parent && - node.parent.type === 'CallExpression' && - node.parent.callee && - node.parent.callee.type === 'Identifier' && - node.parent.callee.name === 'require' && - node.parent.parent && - node.parent.parent.type === 'ArrayExpression' - ); -} - -function formatBundleInfo(bundleName, moduleList) { - var enumeration = moduleList.map(function(moduleName, i) { - var len = moduleList.length, - ending; - - if(i === len - 2) ending = ' and'; - else if(i < len - 1) ending = ','; - else ending = ''; - - return '`' + moduleName + '`' + ending; - }); - - return [ - 'The', '`' + bundleName + '`', - 'partial bundle contains the', - enumeration.join(' '), - 'trace modules.' - ].join(' '); -} diff --git a/tasks/sync_packages.js b/tasks/sync_packages.js new file mode 100644 index 00000000000..2002c3d4ca9 --- /dev/null +++ b/tasks/sync_packages.js @@ -0,0 +1,139 @@ +var path = require('path'); +var fs = require('fs-extra'); +var exec = require('child_process').exec; +var runSeries = require('run-series'); + +var common = require('./util/common'); +var constants = require('./util/constants'); +var pkg = require('../package.json'); + +var packagesSpecs = constants.partialBundlePaths + .map(function(d) { + return { + name: 'plotly.js-' + d.name + '-dist', + index: d.index, + main: 'plotly-' + d.name + '.js', + dist: d.dist, + desc: 'Ready-to-use plotly.js ' + d.name + ' distributed bundle.', + }; + }) + .concat([{ + name: 'plotly.js-dist', + index: path.join(constants.pathToLib, 'index.js'), + main: 'plotly.js', + dist: constants.pathToPlotlyDist, + desc: 'Ready-to-use plotly.js distributed bundle.', + }]); + +packagesSpecs.forEach(function(d) { + var pkgPath = path.join(constants.pathToBuild, d.name); + + function initDirectory(cb) { + if(common.doesDirExist(pkgPath)) { + cb(); + } else { + fs.mkdir(pkgPath, cb); + } + } + + function writePackageJSON(cb) { + var cnt = { + name: d.name, + version: pkg.version, + description: d.desc, + license: pkg.license, + main: d.main, + repository: pkg.repository, + bugs: pkg.bugs, + author: pkg.author, + keywords: pkg.keywords, + files: [ + 'LICENSE', + 'README.md', + d.main + ] + }; + + fs.writeFile( + path.join(pkgPath, 'package.json'), + JSON.stringify(cnt, null, 2) + '\n', + cb + ); + } + + function writeREADME(cb) { + var moduleList = common.findModuleList(d.index); + + var cnt = [ + '# ' + d.name, + '', + d.desc, + '', + 'Contains trace modules ' + common.formatEnumeration(moduleList) + '.', + '', + 'For more info on plotly.js, go to https://github.com/plotly/plotly.js', + '', + '## Installation', + '', + '```', + 'npm install ' + d.name, + '```', + '## Usage', + '', + '```js', + '// ES6 module', + 'import Plotly from \'' + d.name + '\';', + '', + '// CommonJS', + 'var Plotly = require(\'' + d.name + '\');', + '```', + '', + '## Copyright and license', + '', + 'Code and documentation copyright 2018 Plotly, Inc.', + '', + 'Code released under the [MIT license](https://github.com/plotly/plotly.js/blob/master/LICENSE).', + '', + 'Docs released under the [Creative Commons license](https://github.com/plotly/documentation/blob/source/LICENSE).', + '' + ]; + + fs.writeFile( + path.join(pkgPath, 'README.md'), + cnt.join('\n'), + cb + ); + } + + function copyMain(cb) { + fs.copy(d.dist, path.join(pkgPath, d.main), cb); + } + + function copyLicense(cb) { + fs.copy( + path.join(constants.pathToRoot, 'LICENSE'), + path.join(pkgPath, 'LICENSE'), + cb + ); + } + + function publishToNPM(cb) { + if(process.env.DRYRUN) { + console.log('dry run, did not publish ' + d.name); + cb(); + return; + } + exec('npm publish', {cwd: pkgPath}, cb).stdout.pipe(process.stdout); + } + + runSeries([ + initDirectory, + writePackageJSON, + writeREADME, + copyMain, + copyLicense, + publishToNPM + ], function(err) { + if(err) throw err; + }); +}); diff --git a/tasks/util/common.js b/tasks/util/common.js index b9330febd56..e3dcd6859c1 100644 --- a/tasks/util/common.js +++ b/tasks/util/common.js @@ -1,5 +1,6 @@ var fs = require('fs'); var exec = require('child_process').exec; +var falafel = require('falafel'); exports.execCmd = function(cmd, cb, errorCb) { cb = cb ? cb : function() {}; @@ -66,3 +67,41 @@ exports.touch = function(filePath) { exports.throwOnError = function(err) { if(err) throw err; }; + +exports.findModuleList = function(pathToIndex) { + var code = fs.readFileSync(pathToIndex, 'utf-8'); + // In v1.x, all partial bundles include the 'scatter' module + var moduleList = ['scatter']; + + falafel(code, function(node) { + if( + node.type === 'Literal' && + node.parent && + node.parent.type === 'CallExpression' && + node.parent.callee && + node.parent.callee.type === 'Identifier' && + node.parent.callee.name === 'require' && + node.parent.parent && + node.parent.parent.type === 'ArrayExpression' + ) { + var moduleName = node.value.replace('./', ''); + moduleList.push(moduleName); + } + }); + + return moduleList; +}; + +exports.formatEnumeration = function(list) { + var len = list.length; + + return list.map(function(l, i) { + var ending; + + if(i === len - 2) ending = ' and'; + else if(i < len - 1) ending = ','; + else ending = ''; + + return '`' + l + '`' + ending; + }).join(' '); +};