Imagine you have a very large application. And you have your application divided into multiple apps. And not all apps need to be served to the browser at the same time since they target different pages.
To serve them individually, we can bundle them separately and load them independently via <script>
tags.
We can divide our bundles like this:
vendors.js
: contains Lodash, RxJS, Frint, etcroot.js
: our Root app's bundleapp-foo.js
: App Foo's bundleapp-bar.js
: App Bar's bundleWe also want to make sure that our root and app bundles would not duplicate any of the libraries that we already have in vendors.js
.
Illustration of a multiple bundles loading themselves in the browser, and then rendering the final output.
We will see some code examples below.
First the vendors:
$ npm install --save lodash rxjs react react-dom prop-types frint frint-store frint-model frint-react
And the devDependencies for bundling:
$ npm install --save babel-core babel-loader babel-preset-travix webpack
Goal is to generate a vendors.js
file, which once loaded in the browser would expose the dependencies directly under window
object.
The entry file for the budle can look something like this:
// vendors_entry.js
window._ = require('lodash');
window.Rx = require('rxjs');
window.React = require('react');
window.ReactDOM = require('react-dom');
window.Frint = require('frint');
window.FrintStore = require('frint-store');
window.FrintModel = require('frint-model');
window.FrintReact = require('frint-react');
The webpack configuration may look something like this:
// vendors-webpack.config.js
module.exports = {
entry: __dirname + '/vendors_entry.js',
output: {
path: __dirname + '/build/js',
filename: 'vendors.js'
}
};
Running this command now would generate a new file at ./build/vendors.js
:
$ ./node_modules/.bin/webpack --config ./vendors-webpack.config.js
We can create a file for listing all our dependencies' names, that we can reuse in webpack configuration for our App bundles:
// externals.js
module.exports = {
// npm package name => name under `window` in browser
'lodash': '_',
'rxjs': 'Rx',
'react': 'React',
'react-dom': 'ReactDOM',
'frint': 'Frint',
'frint-store': 'FrintStore',
'frint-model': 'FrintModel',
'frint-react': 'FrintReact'
};
We also ship a list of externals
from our internally used frint-config
package that may help reduce your boilerplate:
// externals.js
const config = require('frint-config');
module.exports = []
.concat(config.lodashExternals)
.concat(config.rxjsExternals)
.concat(config.thirdPartyExternals)
.concat(config.frintExternals);
Webpack config for your root app may look like this:
// root-webpack.config.js
const externals = require('./externals');
module.exports = {
entry: __dirname + '/path/to/root/app/entry',
output: {
path: __dirname + '/build',
filename: 'root.js'
},
module: {
rules: [
{
test: /\.(js)$/,
loader: 'babel-loader',
query: {
presets: [
'travix'
]
}
}
]
},
// we reuse the same externals list across all configuration files
externals: externals,
};
Running this command would then generate ./build/rootApp.js
file:
$ ./node_modules/.bin/webpack --config root-webpack.config.js
The entry file of your root app may look like this:
import { render } from 'frint-react';
import App from './app';
window.app = new App();
render(window.app, document.getElementById('root'));
Apps bundling can follow the same approach as root app bundling like above.
The entry file of an App may look like this:
import App from './app';
window.app.registerApp(App, {
regions: ['sidebar']
});
Visit the Async loading guide to learn how you can loading root and child apps asynchronously.