diff --git a/packages/subapp-server/src/index-page.jsx b/packages/subapp-server/src/index-page.jsx
index 54e934c9d..32e3cae36 100644
--- a/packages/subapp-server/src/index-page.jsx
+++ b/packages/subapp-server/src/index-page.jsx
@@ -1,6 +1,7 @@
/* @jsx createElement */
import { IndexPage, createElement, Token, Require } from "../template";
+import { ReserveSpot } from "subapp-web";
const RenderSubApps = (props, context) => {
const { routeOptions } = context.user;
@@ -46,6 +47,7 @@ const Template = (
+
diff --git a/packages/subapp-web/lib/ReserveSpot.js b/packages/subapp-web/lib/ReserveSpot.js
new file mode 100644
index 000000000..200deaccf
--- /dev/null
+++ b/packages/subapp-web/lib/ReserveSpot.js
@@ -0,0 +1,10 @@
+"use strict";
+
+const ReserveSpot = (props, context) => {
+ if (props.saveId) {
+ const spot = context.output.reserve();
+ context.user[props.saveId] = spot;
+ }
+};
+
+module.exports = ReserveSpot;
diff --git a/packages/subapp-web/lib/index.js b/packages/subapp-web/lib/index.js
index e64b93717..daf23cb99 100644
--- a/packages/subapp-web/lib/index.js
+++ b/packages/subapp-web/lib/index.js
@@ -8,6 +8,7 @@ const { default: makeSubAppSpec } = require("../dist/node/make-subapp-spec");
const { setupFramework } = require("./util");
const lazyLoadSubApp = () => {};
+const ReserveSpot = require("./ReserveSpot");
module.exports = {
// isomorphic functions
@@ -29,5 +30,6 @@ module.exports = {
init: require("./init"),
load: require("./load"),
start: require("./start"),
+ ReserveSpot,
xarc: { IS_BROWSER: false, HAS_WINDOW: false } // no xarc client lib on the server
};
diff --git a/packages/subapp-web/lib/load.js b/packages/subapp-web/lib/load.js
index 37e7fc8c3..312bfdaf8 100644
--- a/packages/subapp-web/lib/load.js
+++ b/packages/subapp-web/lib/load.js
@@ -145,6 +145,7 @@ Response: ${err || body}`
const cdnJsBundles = util.getCdnJsBundles(assets, setupContext.routeOptions);
const bundles = entryPoints.filter(ep => !includedBundles[ep]);
+ const headSplits = [];
const splits = bundles
.map(ep => {
if (!inlineSubAppJs && !includedBundles[entryName]) {
@@ -153,16 +154,24 @@ Response: ${err || body}`
cdnJsBundles[ep] &&
[]
.concat(cdnJsBundles[ep])
- .map(jsBundle => {
+ .reduce((a, jsBundle) => {
const ext = Path.extname(jsBundle);
if (ext === ".js") {
- return ``;
+ if (context.user.headEntries) {
+ headSplits.push(``);
+ }
+ a.push(``);
} else if (ext === ".css") {
- return ``;
+ if (context.user.headEntries) {
+ headSplits.push(``);
+ } else {
+ a.push(``);
+ }
} else {
- return ``;
+ a.push(``);
}
- })
+ return a;
+ }, [])
.join("\n")
);
}
@@ -179,7 +188,7 @@ Response: ${err || body}`
}
}
- return { bundles, scripts: splits.join("\n") };
+ return { bundles, scripts: splits.join("\n"), preLoads: headSplits.join("\n") };
};
const loadSubApp = () => {
@@ -210,6 +219,8 @@ Response: ${err || body}`
const { request } = context.user;
+ context.user.numOfSubapps = context.user.numOfSubapps || 0;
+
if (request.app.webpackDev && subAppLoadTime < request.app.webpackDev.compileTime) {
subAppLoadTime = request.app.webpackDev.compileTime;
loadSubApp();
@@ -312,6 +323,11 @@ ${stack}`,
}
outputSpot.close();
+ context.user.numOfSubapps--;
+ if (context.user.numOfSubapps === 0 && context.user.headEntries) {
+ context.user.headEntries.close();
+ context.user.headEntries = undefined;
+ }
};
ssrInfo.done = () => {
@@ -329,13 +345,19 @@ ${stack}`,
ssrGroups
};
- const { bundles, scripts } = await prepareSubAppSplitBundles(context);
+ context.user.numOfSubapps++;
+ const { bundles, scripts, preLoads } = await prepareSubAppSplitBundles(context);
outputSpot.add(`${comment}`);
if (bundles.length > 0) {
outputSpot.add(`${scripts}
`);
}
+ if (preLoads.length > 0) {
+ context.user.headEntries.add("\n");
+ context.user.headEntries.add(preLoads);
+ context.user.headEntries.add("\n");
+ }
if (props.serverSideRendering) {
const lib = (ssrInfo.lib = util.getFramework(ref));
diff --git a/packages/subapp-web/package.json b/packages/subapp-web/package.json
index 091663317..a738121b5 100644
--- a/packages/subapp-web/package.json
+++ b/packages/subapp-web/package.json
@@ -48,7 +48,8 @@
"jsdom": "^15.2.1",
"mock-require": "^1.3.0",
"run-verify": "^1.2.2",
- "subapp-pkg-util": "../subapp-pkg-util"
+ "subapp-pkg-util": "../subapp-pkg-util",
+ "electrode-react-webapp": "^3.8.9"
},
"fyn": {
"dependencies": {
diff --git a/packages/subapp-web/test/spec/load.spec.js b/packages/subapp-web/test/spec/load.spec.js
index e69de29bb..f60ab1db9 100644
--- a/packages/subapp-web/test/spec/load.spec.js
+++ b/packages/subapp-web/test/spec/load.spec.js
@@ -0,0 +1,83 @@
+"use strict";
+
+const { load } = require("../../lib");
+const utils = require("../../lib/util");
+const Path = require("path");
+const reserveSpot = require("../../lib/ReserveSpot");
+const RenderOutput = require("electrode-react-webapp/lib/render-output");
+
+describe("load", function () {
+ const statsPath = Path.join(__dirname, "../data/dev-stats.json");
+ const { assets } = utils.loadAssetsFromStats(statsPath);
+ let context;
+ let setUpContext;
+ let props;
+
+ beforeEach(() => {
+ setUpContext = {
+ routeOptions: {
+ cdn: {},
+ __internals: {
+ assets
+ }
+ }
+ };
+ context = {
+ user: {
+ request: { app: {} },
+ assets,
+ includedBundles: {}
+ },
+ transform: x => x
+ };
+ props = {
+ props: {
+ serverSideRendering: false
+ }
+ };
+ utils.resetCdn();
+ });
+
+ afterEach(() => {
+ delete process.env.NODE_ENV;
+ delete process.env.APP_SRC_DIR;
+ });
+
+ it("should load bundles for the subapp", done => {
+ process.env.APP_SRC_DIR = "test/subapps";
+ const loadToken = load(setUpContext, { props: { name: "mainbody" } });
+
+ context.send = results => {
+ expect(results).to.not.be.empty;
+ expect(context.user.includedBundles).to.include({ mainbody: true });
+ expect(results).to.include(``);
+ expect(results).to.include(
+ ``
+ );
+ expect(context.user.headEntries).to.not.be.ok;
+ done();
+ };
+ context.output = new RenderOutput(context);
+
+ loadToken.process(context, props);
+ context.output.close();
+ });
+
+ it("should load preload tags for scripts", done => {
+ process.env.APP_SRC_DIR = "test/subapps";
+ const loadToken = load(setUpContext, { props: { name: "mainbody" } });
+
+ context.send = results => {
+ expect(results).to.not.be.empty;
+ expect(results).to.include(``);
+ expect(results).to.include(``);
+ expect(context.user.includedBundles).to.include({ mainbody: true });
+ done();
+ };
+ context.output = new RenderOutput(context);
+ reserveSpot({ saveId: "headEntries" }, context);
+
+ loadToken.process(context, props);
+ context.output.close();
+ });
+});
diff --git a/packages/subapp-web/test/subapps/subapp1/src/index.js b/packages/subapp-web/test/subapps/subapp1/src/index.js
new file mode 100644
index 000000000..aa87052be
--- /dev/null
+++ b/packages/subapp-web/test/subapps/subapp1/src/index.js
@@ -0,0 +1,3 @@
+module.exports = {
+ foo: () => 123
+};
diff --git a/packages/subapp-web/test/subapps/subapp1/src/server.js b/packages/subapp-web/test/subapps/subapp1/src/server.js
new file mode 100644
index 000000000..2c9e83352
--- /dev/null
+++ b/packages/subapp-web/test/subapps/subapp1/src/server.js
@@ -0,0 +1,3 @@
+module.exports = {
+ name: "mainbody"
+};
diff --git a/packages/subapp-web/test/subapps/subapp1/src/subapp-conf.js b/packages/subapp-web/test/subapps/subapp1/src/subapp-conf.js
new file mode 100644
index 000000000..3b724396d
--- /dev/null
+++ b/packages/subapp-web/test/subapps/subapp1/src/subapp-conf.js
@@ -0,0 +1,6 @@
+module.exports = {
+ name: "mainbody",
+ subAppDir: "Subapp1/src",
+ entry: "index.js",
+ serverEntry: "server.js"
+};
diff --git a/packages/subapp-web/test/subapps/subapp1/src/subapp-manifest.js b/packages/subapp-web/test/subapps/subapp1/src/subapp-manifest.js
new file mode 100644
index 000000000..926d082e9
--- /dev/null
+++ b/packages/subapp-web/test/subapps/subapp1/src/subapp-manifest.js
@@ -0,0 +1,6 @@
+module.exports = {
+ name: "mainbody",
+ subAppDir: "subapp1/src",
+ entry: "index.js",
+ serverEntry: "server.js"
+};