React multi-app and package build handling for lerna monorepos.
App: webpack serving and building, scss/css support, public folder etc. - similar to create-react-app.
Backends: NodeJS backend server, watching and production build with babel, dev serving with nodemon.
Packages: publishable packages, can be used by apps/backends directly, production built with babel.
Supports: ESNext, React, TypeScript, d.ts Generation, Sass, Code Split compatible, es-modules and commonjs, Jest and Testing Library, ...
npm init
npm i --save lerna lerna-packer
experimental, fix the version without any modifier
Add packerConfig.js
with configs for apps and packages (e.g. component libraries, shared universal JS).
check typescript definition for full configuration options
const path = require('path');
const {packer} = require('lerna-packer');
packer(
// apps and packages are required, backends are optional
{
apps: {
docs: {
port: 9219,// only for serving / webpack dev-server
root: path.resolve(__dirname, 'packages', '_docs-control'),
template: path.resolve(__dirname, 'packages', '_docs-control/public/index.html'),
contentBase: path.resolve(__dirname, 'packages', '_docs-control/public'),// also the root for the dev-server
main: path.resolve(__dirname, 'packages', '_docs-control/src/index.tsx'),
//entries: {},// further webpack entries for this app
dist: path.resolve(__dirname, 'dist', 'docs-control'),
publicPath: '/',
plugins: [],
},
},
backends: {
someApi: {
root: path.resolve(__dirname, 'packages', 'some-api'),
src: 'src',
entry: 'server.js',
},
},
packages: {
// the keys are the commonjs names that is applied to externals
// this is the same as `@babel/plugin-transform-modules-commonjs` applies
controlKit: {
name: '@control-ui/kit',
root: path.resolve(__dirname, 'packages', 'control-kit'),
entry: path.resolve(__dirname, 'packages', 'control-kit/src/'),
},
controlApp: {
name: '@control-ui/app',
root: path.resolve(__dirname, 'packages', 'control-app'),
entry: path.resolve(__dirname, 'packages', 'control-app/src/'),
},
}
},
__dirname,
// optional, additional global packer config:
{
pathPackagesBuild: 'build',
pathPackages: 'packages',
onAppBuild: (appsConfigs, stats, configs) => {
return Promise.resolve(undefined)
},
}
)
.then(([execs, elapsed]) => {
if(execs.indexOf('doServe') !== -1) {
console.log('[packer] is now serving (after ' + elapsed + 'ms)')
// do not exit when serving!
} else {
console.log('[packer] finished successfully (after ' + elapsed + 'ms)', execs)
process.exit(0)
}
})
.catch((e) => {
console.error('[packer] finished with error(s)', e)
process.exit(1)
})
Add scripts to package.json
to handle serving, building for developer and CI.
- see command with
node packerConfig.js
for thelerna-packer
CLI commands - see command with
lerna
for thelerna
CLI commands - use:
npm start
for local dev build & servenpm run build
for production ready buildnpm run tdd
for test-driven development (jest)npm i && npm run bootstrap && npm run link
for initial setup / afterpackage.json
changesnpm run clean && rm -rf node_modules
for cleanup ofdist
/build folders andnode_modules
foldersnpm run clean-dist
for cleanup of onlydist
/build foldersnpm run release
for npm / registry publishing of thepackages
(not apps/backends)
{
"scripts": {
"start": "npm run clean-dist && npm run serve",
"serve": "cross-env NODE_ENV=development node packerConfig.js --serve",
"prebuild": "npm run clean-dist",
"build": "npm run build-all && npm run dtsgen",
"build-all": "cross-env NODE_ENV=production CI=true node packerConfig.js --build --babel --backend --webpack",
"build-babel": "cross-env NODE_ENV=production CI=true node packerConfig.js --build --babel",
"build-backend": "cross-env NODE_ENV=production CI=true node packerConfig.js --build --backend",
"build-webpack": "cross-env NODE_ENV=production CI=true node packerConfig.js --build --webpack",
"clean": "npm run clean-dist && lerna clean -y",
"clean-dist": "node packerConfig.js --clean",
"link": "lerna link --force-local",
"dtsgen": "lerna run dtsgen",
"bootstrap": "lerna bootstrap",
"hoist": "lerna bootstrap --hoist",
"test": "jest -c=\"packages/jest.config.js\"",
"tdd": "npm test -- --watch --watchman --coverage=false",
"release": "lerna publish from-package --contents build --no-git-reset"
}
}
Add babel.config.json
or similar:
{
"presets": [
[
"@babel/preset-react",
{
"loose": false
}
],
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-syntax-dynamic-import",
"@babel/plugin-transform-react-jsx",
"@babel/plugin-transform-template-literals",
"@babel/plugin-proposal-optional-chaining",
"@babel/plugin-proposal-export-namespace-from",
"@babel/plugin-proposal-export-default-from",
"@babel/plugin-transform-runtime",
"transform-es2015-template-literals",
"react-loadable/babel",
[
"babel-plugin-named-asset-import",
{
"loaderMap": {
"svg": {
"ReactComponent": "@svgr/webpack?-svgo,+titleProp,+ref![path]"
}
}
}
],
[
"@babel/plugin-proposal-object-rest-spread",
{
"useBuiltIns": true
}
],
[
"@babel/plugin-proposal-class-properties",
{
"loose": true
}
]
],
"env": {
"cjs": {
"presets": [
[
"@babel/preset-env",
{
"loose": false
}
],
[
"@babel/preset-react",
{
"loose": false
}
],
[
"@babel/preset-typescript",
{
"loose": false
}
]
]
},
"test": {
"presets": [
"@babel/preset-env",
"@babel/preset-typescript"
],
"plugins": [
"@babel/plugin-transform-modules-commonjs"
]
},
"node": {
"presets": [
[
"@babel/preset-env",
{
"targets": {
"node": "14"
},
"modules": false
}
],
[
"@babel/preset-typescript",
{
"targets": {
"node": "14"
},
"modules": false
}
]
]
}
}
}
Add the following part into package.json
for fatal errors on warnings for eslint in jest:
{
"jest-runner-eslint": {
"cliOptions": {
"maxWarnings": 0
}
},
"nodemonConfig": {
"delay": 140
}
}
Add .eslintrc
, tsconfig.json
, jest.config.js
in root/packages/package-dirs like wanted.
Usage examples, check the packerConfig.js
there:
- UI Schema
- Control UI
- Icon1, incl.
backends
This project is free software distributed under the MIT License.
See: LICENSE.
© 2022 Michael Becker
By committing your code/creating a pull request to this repository you agree to release the code under the MIT License attached to the repository.