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

Loading subapps from a different repo #1700

Merged
merged 13 commits into from
Jul 16, 2020
Merged
14 changes: 11 additions & 3 deletions packages/subapp-server/lib/setup-hapi-routes.js
Original file line number Diff line number Diff line change
Expand Up @@ -106,17 +106,25 @@ function setupRouteRender({ subAppsByPath, srcDir, routeOptions }) {
// load subapps for the route
if (routeOptions.subApps) {
routeOptions.__internals.subApps = [].concat(routeOptions.subApps).map(x => {
let options = {};
let options;
if (Array.isArray(x)) {
options = x[1];
x = x[0];
}
// absolute: use as path
// module: resolve module path
// else: assume dir under srcDir
// TBD: handle it being a module
if (!x.startsWith(".") && !x.startsWith("/")) {
const subAppPath = optionalRequire.resolve(x);
if (subAppPath) {
const { manifest, subAppOptions } = require(x);
x = manifest ? Path.dirname(subAppPath) : x;
options = options || subAppOptions;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added this to support passing subapp options from main app also. This will be useful in use-cases where main app wants to customize the options for individual subapps.

}
}
return {
subapp: subAppsByPath[Path.isAbsolute(x) ? x : Path.resolve(srcDir, x)],
options
options: options || {}
};
});
}
Expand Down
54 changes: 47 additions & 7 deletions packages/subapp-util/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
const Url = require("url");
const Path = require("path");
const assert = require("assert");
const _ = require("lodash");
const optionalRequire = require("optional-require")(require);
const scanDir = require("filter-scan-dir");
const appMode = optionalRequire(Path.resolve(".prod/.app-mode.json"), { default: {} });
Expand All @@ -29,6 +30,18 @@ function removeExt(f) {
return ix > 0 ? f.substring(0, ix) : f;
}

const validateModuleManifest = manifest => {
const entries = _.pick(manifest, ["entry", "serverEntry", "reducers"]);
Object.keys(entries).forEach(x => {
if (!Path.isAbsolute(entries[x])) {
throw new Error(
`Could not resolve subapp ${x} "${entries[x]}".\
Please provide absolute path to the ${x} in subapp manifest`
);
}
});
};

//
// scan a subapp's directory for additional things:
// - server side entry in server.js, server-{name}.js, server-{verbatimName}.js
Expand Down Expand Up @@ -122,11 +135,12 @@ function scanSubAppsFromDir(srcDir, maxLevel = Infinity) {
const fullSrcDir = Path.resolve(srcDir);

const subApps = { [MAP_BY_PATH_SYM]: {} };
const { maniFiles = [], files = [] } = scanDir.sync({
const { maniFiles = [], files = [], modFiles = [] } = scanDir.sync({
dir: srcDir,
grouping: true,
maxLevel,
filter: (f, p, ex) => {
if (ex.noExt === "subapps-modules") return "modFiles";
if (ex.noExt === "subapp-manifest") return "maniFiles";
return f.startsWith("subapp");
},
Expand Down Expand Up @@ -162,7 +176,25 @@ function scanSubAppsFromDir(srcDir, maxLevel = Infinity) {
return null;
});

const errors = [].concat(errors1, errors2).filter(x => x);
// process subapps modules
let errors3 = [];
if (modFiles.length > 0) {
const manifests = es6Require(Path.join(fullSrcDir, modFiles[0]));
errors3 = Object.keys(manifests).map(modName => {
try {
const manifest = manifests[modName];
validateModuleManifest(manifest);
const modFullDir = Path.dirname(require.resolve(modName));
const subapp = Object.assign({ subAppDir: modName, module: true }, manifest);
subApps[manifest.name] = subApps[MAP_BY_PATH_SYM][modFullDir] = subapp;
} catch (error) {
return error;
}
return null;
});
}

const errors = [].concat(errors1, errors2, errors3).filter(x => x);
if (errors.length > 0) {
console.error("Loading SubApps failed");
errors.forEach(err => {
Expand Down Expand Up @@ -242,7 +274,7 @@ function loadSubAppByName(name) {
const container = getSubAppContainer();
const subAppDir = manifest.subAppDir;
// load subapp's entry
xrequire(Path.resolve(appSrcDir(), subAppDir, manifest.entry));
xrequire(manifest.module ? manifest.entry : Path.resolve(appSrcDir(), subAppDir, manifest.entry));

// if subapp did not register itself then register it
if (!container[name]) {
Expand All @@ -258,13 +290,17 @@ function loadSubAppServerByName(name) {
const { subAppDir, serverEntry } = manifest;

if (serverEntry) {
return es6Require(Path.resolve(appSrcDir(), subAppDir, serverEntry));
return es6Require(
manifest.module ? serverEntry : Path.resolve(appSrcDir(), subAppDir, serverEntry)
);
} else if (serverEntry === false) {
return {};
}

// generate a server from subapp's main file
const subapp = es6Require(Path.resolve(appSrcDir(), subAppDir, manifest.entry));
const subapp = es6Require(
manifest.module ? manifest.entry : Path.resolve(appSrcDir(), subAppDir, manifest.entry)
);

return {
StartComponent: subapp.Component
Expand All @@ -275,11 +311,15 @@ function refreshSubAppByName(name) {
const manifest = subAppManifest()[name];
const { subAppDir } = manifest;

const entryFullPath = xrequire.resolve(Path.resolve(appSrcDir(), subAppDir, manifest.entry));
const entryFullPath = xrequire.resolve(
manifest.module ? manifest.entry : Path.resolve(appSrcDir(), subAppDir, manifest.entry)
);
if (!xrequire.cache[entryFullPath] && manifest.serverEntry) {
// also reload server side module
const serverEntryFullPath = xrequire.resolve(
Path.resolve(appSrcDir(), subAppDir, manifest.serverEntry)
manifest.module
? manifest.serverEntry
: Path.resolve(appSrcDir(), subAppDir, manifest.serverEntry)
);
console.log("reloading server side subapp", name, serverEntryFullPath);
delete xrequire.cache[serverEntryFullPath];
Expand Down
11 changes: 7 additions & 4 deletions packages/xarc-webpack/lib/partials/entry.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,21 +52,24 @@ function makeEntryPartial() {
}

function genSubAppHmrEntry(hmrDir, isDev, manifest) {
let subAppReq = `${manifest.subAppDir}/${manifest.entry}`;
let subAppReq = manifest.module ? manifest.entry : `${manifest.subAppDir}/${manifest.entry}`;

// subapp has built-in code to handle HMR accept
// or not running in webpack dev mode
// => do not generate HMR accept code
if (manifest.hmrSelfAccept || !isDev) {
return `./${subAppReq}`;
return manifest.module ? subAppReq : `./${subAppReq}`;
}

const hmrEntry = `hmr-${manifest.subAppDir.replace(/[\/\\]/g, "-")}.js`;
subAppReq = `../${subAppReq}`;
subAppReq = manifest.module ? subAppReq : `../${subAppReq}`;

let reducerHmrCode = "";

if (manifest.reducers) {
const subAppReducers = `../${manifest.subAppDir}/reducers`;
const subAppReducers = manifest.module
? manifest.reducers
: `../${manifest.subAppDir}/reducers`;
reducerHmrCode = `
import { getReduxCreateStore } from "subapp-redux";
import reducers from "${subAppReducers}";
Expand Down
1 change: 1 addition & 0 deletions samples/demo-tree-shaking/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"lodash": "^4.17.10",
"milligram": "^1.3.0",
"react-intl": "^3.11.0",
"intl-format-cache": "4.2.46",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To fix the build issue

"react-notify-toast": "^0.4.1",
"react-router-config": "^5.1.1"
},
Expand Down
5 changes: 2 additions & 3 deletions samples/react-jest-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@
"@xarc/app-dev": "^5.3.4",
"electrode-archetype-opt-critical-css": "^1.0.3",
"electrode-archetype-opt-eslint": "^1.0.3",
"electrode-archetype-opt-jest": "^25.0.0",
"electrode-archetype-opt-jest": "^26.0.0",
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed to match the version with latest publish

"electrode-archetype-opt-less": "^1.0.2",
"electrode-archetype-opt-mocha": "^1.0.3",
"electrode-archetype-opt-phantomjs": "^1.0.2",
Expand All @@ -80,8 +80,7 @@
"electrode-auto-ssr": "../../packages/electrode-auto-ssr"
},
"devDependencies": {
"@xarc/app-dev": "../../packages/xarc-app-dev",
"electrode-archetype-opt-jest": "../../packages/electrode-archetype-opt-jest"
"@xarc/app-dev": "../../packages/xarc-app-dev"
}
},
"optionalDependencies": {}
Expand Down