Work-in-progress
React-union-scripts
Extendable and configurable set of scripts for building and running your React applications that is designed for not a typical Node environments such as Content Management Systems (CMS) or Java Portals.
Main features
- simple to use - just add the dependency to your
package.json
and roll - use multiple entry points in one project - useful for theming or for splitting your code to optimize bundle size
- designed for large codebase - multiple entry points, splitting code, async loading of JavaScript modules
Installation
yarn add react react-dom && yarn add react-union-scripts --dev
or
npm install react react-dom && npm install --save-dev react-union-scripts
Usage
TL;DR You can use one of our examples as a boilerplate for your project instead.
- Simulate output of your server in development
Create <project root>/public/YourAppName/index.ejs
:
<%= htmlWebpackPlugin.options.title %>
For details how to write a template, see https://github.com/jantimon/html-webpack-plugin.
- To your
package.json
add scripts:
- Create
<project root>/src/apps/YourAppName/index.js
:
import React from 'react';import render from 'react-dom'; ;
- Run your project
Development server
yarn start --app YourAppName
Start proxy server
yarn start --app YourAppName --proxy
Production build
Build all registered apps.
yarn build --release
or build just one
yarn build --app YourAppName --release
Running Jest tests
Run in watch mode
yarn test
or run just once
yarn test --release
Analyze build
Runs webpack-bundle-analyzer
.
yarn start --app YourAppName --analyze
CLI
analyze
- available for:
start
Runs webpack-bundle-analyzer
.
Example:
react-union-scripts start --app MyApp --analyze
app
- available for:
start
,build
Determines what application to build or start.
Example:
react-union-scripts start --app MyApp
no-hmr
- available for:
start
,build
If is set, hot module replacement is off.
Example:
react-union-scripts start --no-hmr
proxy
- available for:
start
.
If is set, we start proxy server instead of development server.
Example:
react-union-scripts start --proxy
release
- available for:
start
,build
If is set, the build is optimized for production.
Example:
react-union-scripts build --release
target
- available for:
start
,build
Custom value that can be used in union.config.js
.
Example:
react-union-scripts build --target wordpress
verbose
- available for:
start
,build
If is set, the console output is more verbose.
Example:
react-union-scripts build --verbose
union.config.js
Place the file into the root of your project if you want to configure react-union-scripts.
Configuration file can export either:
- static JSON object or
- function.
To the function is passed object that describes flags derived from calling our CLI api:
// example of dynamic union.config.jsmoduleexports = target // custom value script // build, start or test app debug proxy verbose noHmr analyze outputMapper: target === 'liferay' ? js: 'widgets/js' : {};
Resulting configuration can redefine following properties.
devServer
[devServer.port
](number): port of proxy server
proxy
[proxy.port
](number): port of proxy server
[proxy.target
](string): target of proxy
[proxy.publicPath
](string): Public path of the application. See webpack. Required if you want to run proxy.
outputMapper
Output mapper makes possible further customization of the folder structure that is produced by the build. All paths are relative to the apps[].paths.build
directory.
[outputMapper.js
](string): Path of JavaScript assets. Defaults to static/js
.
[outputMapper.media
](string): Path of media assets. Defaults to static/media
.
apps
Array of configurations for your applications. Every configuration is merged with above properties. You can rewrite them separately for every application.
For example in the config:
moduleexports = proxy: port: 3333 apps: name: 'MyFirstApp' proxy: port: 5000 name: 'MySecondApp' ;
MyFirstApp will use proxy port 5000
and MySecondApp will use common value 3333
.
[apps[].name
](string): Name of your application that is used for both:
- finding HTML template in
./public
directory and - naming your bundle file. Required.
[apps[].paths.build
](string) Path to the build directory. Defaults to <project root>/build/[ApplicationName]
.
[apps[].paths.public
](string) Path to public directory. Directory should contain:
- static assets, that will be copied to the build directory
- a HTML template that is named according to
templateFilename
property. Defaults to<project root>/public/[ApplicationName]
.
[apps[].paths.index
](string) Path to entry file of a the application. Defaults to <project root>/apps/[ApplicationName]
.
templateFilename
[templateFilename
](string): Name of the HTML template. Defaults to index.ejs
.
generateVendorBundle
[generateVendorBundle
](boolean) If true, generates separate vendor chunk. Vendors are all dependencies from your package.json
. Defaults to true
.
vendorBlackList
['vendorBlackList'](array[string]) List of depenedencies that should not be included within vendor chunk. Defaults to []
.
mergeWebpackConfig
[mergeWebpackConfig
](function) If specified, webpack.config
generated by react-union-scripts
is passed as the argument. Function must return new valid webpack config.
Recipes
webpack.config
Extending If you need customize webpack.config generated by react-union-scripts
, specify function mergeWebpackConfig
in union.config.js
.
moduleexports = { console;// Outputs:// {// "context": "...",// "entry": {// "vendor": [...],// "SampleApp": [...]// },// "output": {...},// "plugins": [...],// "resolve": {...},// "module": {...}// } return config; };
Merging webpack.configs can be tedious task. To make it little bit simplier we recommend to use webpack-merge library.
Install it by running:
yarn add -D webpack-merge
in the root of your project. Than use it in union.config.js
, e.g.:
const merge = ; module ;
.ejs
templates for mocking the server output
Create your .ejs template at /public/<YourAppName>/index.ejs
.
YourAppName
refers to application registered within union.config.js
.
Asynchronous loading of modules
If there is a file with suffix ".widget.js" it is loaded by bundle-loader. Bundle-loader is better alternative to both require.ensure
and [import()
];
Every async module is splitted up into individual chunks.
Example
// MyWidget.widget.js const MyWidget = { // Your React component}; ;
// MyWidgetRoute.js ; path: 'my-widget' { ; };