Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make moment optional from our UMD builds #5978

Merged
merged 5 commits into from
Jan 29, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
62 changes: 56 additions & 6 deletions docs/getting-started/integration.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,26 +11,76 @@ Chart.js can be integrated with plain JavaScript or with different module loader
</script>
```

## Webpack
## Common JS

```javascript
import Chart from 'chart.js';
var Chart = require('chart.js');
var myChart = new Chart(ctx, {...});
```

## Common JS
## Bundlers (Webpack, Rollup, etc.)

```javascript
var Chart = require('chart.js');
import Chart from 'chart.js';
var myChart = new Chart(ctx, {...});
```

**Note:** Moment.js is installed along Chart.js as dependency. If you don't want to use Momemt.js (either because you use a different date adapter or simply because don't need time functionalities), you will have to configure your bundler to exclude this dependency (e.g. using [`externals` for Webpack](https://webpack.js.org/configuration/externals/) or [`external` for Rollup](https://rollupjs.org/guide/en#peer-dependencies)).

```javascript
// Webpack
{
externals: {
moment: 'moment'
}
}
```

```javascript
// Rollup
{
external: {
['moment']
}
}
```

## Require JS

**Important:** RequireJS [can **not** load CommonJS module as is](https://requirejs.org/docs/commonjs.html#intro), so be sure to require one of the UMD builds instead (i.e. `dist/Chart.js`, `dist/Chart.min.js`, etc.).

```javascript
require(['path/to/chartjs/dist/Chart.js'], function(Chart) {
require(['path/to/chartjs/dist/Chart.min.js'], function(Chart){
var myChart = new Chart(ctx, {...});
});
```

> **Important:** RequireJS [can **not** load CommonJS module as is](https://requirejs.org/docs/commonjs.html#intro), so be sure to require one of the built UMD files instead (i.e. `dist/Chart.js`, `dist/Chart.min.js`, etc.).
**Note:** starting v2.8, Moment.js is an optional dependency for `Chart.js` and `Chart.min.js`. In order to use the time scale with Moment.js, you need to make sure Moment.js is fully loaded **before** requiring Chart.js. You can either use a shim:

```javascript
require.config({
shim: {
'chartjs': {
deps: ['moment'] // enforce moment to be loaded before chartjs
}
},
paths: {
'chartjs': 'path/to/chartjs/dist/Chart.min.js',
'moment': 'path/to/moment'
}
});

require(['chartjs'], function(Chart) {
new Chart(ctx, {...});
});
```

or simply use two nested `require()`:

```javascript
require(['moment'], function() {
require(['chartjs'], function(Chart) {
new Chart(ctx, {...});
});
});
```
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"license": "MIT",
"jsdelivr": "dist/Chart.min.js",
"unpkg": "dist/Chart.min.js",
"main": "src/chart.js",
"main": "dist/Chart.js",
"keywords": [
"canvas",
"charts",
Expand Down
9 changes: 8 additions & 1 deletion rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
const commonjs = require('rollup-plugin-commonjs');
const resolve = require('rollup-plugin-node-resolve');
const terser = require('rollup-plugin-terser').terser;
const optional = require('./rollup.plugins').optional;
const pkg = require('./package.json');

const input = 'src/chart.js';
Expand All @@ -21,7 +22,10 @@ module.exports = [
input: input,
plugins: [
resolve(),
commonjs()
commonjs(),
optional({
include: ['moment']
})
],
output: {
name: 'Chart',
Expand All @@ -42,6 +46,9 @@ module.exports = [
plugins: [
resolve(),
commonjs(),
optional({
include: ['moment']
}),
terser({
output: {
preamble: banner
Expand Down
61 changes: 61 additions & 0 deletions rollup.plugins.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/* eslint-env es6 */

const UMD_WRAPPER_RE = /(\(function \(global, factory\) \{)((?:\s.*?)*)(\}\(this,)/;
const CJS_FACTORY_RE = /(module.exports = )(factory\(.*?\))( :)/;
const AMD_FACTORY_RE = /(define\()(.*?, factory)(\) :)/;

function optional(config = {}) {
return {
name: 'optional',
renderChunk(code, chunk, options) {
if (options.format !== 'umd') {
this.error('only UMD format is currently supported');
}

const wrapper = UMD_WRAPPER_RE.exec(code);
const include = config.include;
if (!wrapper) {
this.error('failed to parse the UMD wrapper');
}

let content = wrapper[2];
let factory = (CJS_FACTORY_RE.exec(content) || [])[2];
let updated = false;

for (let lib of chunk.imports) {
if (!include || include.indexOf(lib) !== -1) {
const regex = new RegExp(`require\\('${lib}'\\)`);
if (!regex.test(factory)) {
this.error(`failed to parse the CJS require for ${lib}`);
}

// We need to write inline try / catch with explicit require
// in order to enable statical extraction of dependencies:
// try { return require('moment'); } catch(e) {}
const loader = `function() { try { return require('${lib}'); } catch(e) { } }()`;
factory = factory.replace(regex, loader);
updated = true;
}
}

if (!updated) {
return;
}

// Replace the CJS factory by our updated one.
content = content.replace(CJS_FACTORY_RE, `$1${factory}$3`);

// Replace the AMD factory by our updated one: we need to use the
// following AMD form in order to be able to try/catch require:
// define(['require'], function(require) { ... require(...); ... })
// https://github.com/amdjs/amdjs-api/wiki/AMD#using-require-and-exports
content = content.replace(AMD_FACTORY_RE, `$1['require'], function(require) { return ${factory}; }$3`);

return code.replace(UMD_WRAPPER_RE, `$1${content}$3`);
}
};
}

module.exports = {
optional
};