Skip to content

Instantly share code, notes, and snippets.

@jkarttunen
Created April 12, 2020 10:14
Show Gist options
  • Save jkarttunen/741fd48eb441137404a168883238ddc1 to your computer and use it in GitHub Desktop.
Save jkarttunen/741fd48eb441137404a168883238ddc1 to your computer and use it in GitHub Desktop.
Build multiple apps with Create-React-App without ejecting
const { series, src, dest } = require('gulp');
const fs = require('fs');
const del = require('del');
const json = require('json-update');
var rename = require("gulp-rename");
var cp = require('child_process');
const package = require('./package.json');
const deployment = require('./deployment.json');
/*
* Multiple apps are build simply by changing the entry point (index.js), and then running the build script again. This lets us build admin and web/mobile apps to separate bundles.
*/
function cleanBuilds(cb) {
del.sync('builds/**')
cb();
}
function cleanEntrypoint(cb) {
del.sync('src/index.js')
cb();
}
function cleanBuild(cb) {
del.sync('build/**')
cb();
}
function build () {
return cp.exec('npm run CRA:build');
}
function copyBuildToAdmin() {
return src('./build/**')
.pipe(dest('./builds/admin'));
}
function copyBuildToWeb() {
return src('./build/**')
.pipe(dest('./builds'));
}
function changePathsToAdmin(cb) {
json.update('package.json',{ "homepage": "http://<mydomain>/admin",})
.then(function() {
cb();
});
}
function changePathsToWeb(cb) {
json.update('package.json',{ "homepage": "http://<mydomain>.dev",})
.then(function() {
cb();
});
}
function entryPointCustomizer(entry){
return function changeEntryPointFile() {
return src(`./src/entry.${entry}.js`)
.pipe(rename("index.js"))
.pipe(dest('./src'));
}
}
const changeEntryPointFileToAdmin = entryPointCustomizer('admin')
const changeEntryPointFileToWeb = entryPointCustomizer('web')
function saveEntryPointPackageJson() {
return src('./package.json')
.pipe(dest('./.temp'));
}
function restoreEntryPointPackageJson() {
return src('./.temp/package.json')
.pipe(dest('./'));
}
function incrementDeployment(cb) {
json.update('./deployment.json', {
version: package.version,
number: Number(deployment.number) +1
}).then(function() {
cb();
});
}
function copyDeployment() {
return src('./deployment.json')
.pipe(dest('./builds'));
}
function copyDeploymentLocal() {
return src('./deployment.json')
.pipe(dest('./public'));
}
/* Build scripts follow the pattern
1. edit the package.json to have correct entry point for homepage
2. Delete the old entry point
3. Copy the right (admin or web) entry point as the build entry point
4. Run Create-React-App build script to output to /build directory
5. Copy output to combined /builds directory
6. Clean the build directory
*/
const buildAdmin = series(changePathsToAdmin, cleanEntrypoint, changeEntryPointFileToAdmin, build, copyBuildToAdmin, cleanBuild);
const buildWeb = series(changePathsToWeb, cleanEntrypoint, changeEntryPointFileToWeb, build, copyBuildToWeb, cleanBuild);
const preDevWeb = series(changePathsToWeb, cleanEntrypoint, changeEntryPointFileToWeb, copyDeploymentLocal);
const preDevAdmin = series(changePathsToAdmin, cleanEntrypoint, changeEntryPointFileToAdmin, copyDeploymentLocal);
const buildEverything = series(incrementDeployment, buildAdmin, buildWeb, copyDeployment)
exports.build = build;
exports.cleanBuild = cleanBuild;
exports.cleanBuilds = cleanBuilds;
exports.buildAdmin = buildAdmin;
exports.buildWeb = buildWeb;
exports.changePathsToWeb = changePathsToWeb;
exports.cleanEntrypoint = cleanEntrypoint;
exports.changeEntryPointFileToWeb = changeEntryPointFileToWeb;
exports.copyBuildToWeb = copyBuildToWeb;
exports.cleanBuild = cleanBuild;
exports.preDevWeb = preDevWeb;
exports.preDevAdmin = preDevAdmin;
exports.cleanBuilds = cleanBuilds;
exports.saveEntryPointPackageJson = saveEntryPointPackageJson;
exports.restoreEntryPointPackageJson = restoreEntryPointPackageJson;
exports.default = series(cleanBuilds, saveEntryPointPackageJson, buildEverything, restoreEntryPointPackageJson);
exports.incrementDeployment = incrementDeployment;
{
"name": "multi-app CRA",
"version": "0.1.10",
"private": true,
"homepage": "http://<mydomain>",
"dependencies": {
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-scripts": "^3.4.1"
},
"scripts": {
"build": "gulp",
"start": "gulp preDevWeb && npm run CRA:start",
"test": "npm run CRA:test:ci",
"start:web": "gulp preDevWeb && npm run CRA:start",
"start:admin": "gulp preDevAdmin && npm run CRA:start",
"CRA:start": "react-scripts start",
"CRA:build": "react-scripts build",
"CRA:test": "react-scripts test",
"CRA:test:ci": "react-scripts test --watchAll=false",
"CRA:eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"del": "^5.0.0",
"gulp": "^4.0.2",
"gulp-rename": "^2.0.0",
"json-update": "^5.3.0",
},
"proxy": "http://localhost:3001"
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment