diff --git a/bun-plugins/framework.js b/bun-plugins/framework.js
new file mode 100644
index 0000000..9ce248f
--- /dev/null
+++ b/bun-plugins/framework.js
@@ -0,0 +1,25 @@
+const path = require('path');
+const fs = require('fs');
+
+function resolveCliFramework() {
+ const roots = [
+ path.join(__dirname, '..', '..', 'cli', 'config', 'bun', 'framework.js'),
+ path.join(__dirname, '..', '..', '..', 'cli', 'config', 'bun', 'framework.js')
+ ];
+ for (const frameworkPath of roots) {
+ if (fs.existsSync(frameworkPath)) {
+ return require(frameworkPath);
+ }
+ }
+ return null;
+}
+
+async function applyFramework(options = {}) {
+ const cliFramework = resolveCliFramework();
+ if (cliFramework) {
+ return cliFramework.applyFramework(options);
+ }
+ throw new Error('Enact CLI Bun framework module not found.');
+}
+
+module.exports = {applyFramework};
diff --git a/bun-plugins/index.js b/bun-plugins/index.js
new file mode 100644
index 0000000..1034dfb
--- /dev/null
+++ b/bun-plugins/index.js
@@ -0,0 +1,6 @@
+module.exports = {
+ applyPostBuild: require('./post-build').applyPostBuild,
+ applyPrerender: require('./prerender').applyPrerender,
+ applyFramework: require('./framework').applyFramework,
+ applySnapshot: require('./snapshot').applySnapshot
+};
diff --git a/bun-plugins/post-build.js b/bun-plugins/post-build.js
new file mode 100644
index 0000000..492c6b1
--- /dev/null
+++ b/bun-plugins/post-build.js
@@ -0,0 +1,18 @@
+const path = require('path');
+
+function resolveCliModule(subpath) {
+ const roots = [
+ path.join(__dirname, '..', '..', 'cli', subpath),
+ path.join(__dirname, '..', '..', '..', 'cli', subpath)
+ ];
+ for (const candidate of roots) {
+ try {
+ return require(candidate);
+ } catch (e) {
+ // continue
+ }
+ }
+ throw new Error('Unable to resolve CLI Bun module: ' + subpath);
+}
+
+module.exports = resolveCliModule('config/bun/post-build.js');
diff --git a/bun-plugins/prerender.js b/bun-plugins/prerender.js
new file mode 100644
index 0000000..4f073b6
--- /dev/null
+++ b/bun-plugins/prerender.js
@@ -0,0 +1,7 @@
+const PrerenderPlugin = require('../plugins/PrerenderPlugin');
+
+function applyPrerender(options = {}) {
+ return PrerenderPlugin.applyBunPostBuild(options);
+}
+
+module.exports = {applyPrerender, parseLocales: PrerenderPlugin.parseLocales};
diff --git a/bun-plugins/snapshot.js b/bun-plugins/snapshot.js
new file mode 100644
index 0000000..951983b
--- /dev/null
+++ b/bun-plugins/snapshot.js
@@ -0,0 +1,18 @@
+const path = require('path');
+
+function resolveCliModule(subpath) {
+ const roots = [
+ path.join(__dirname, '..', '..', 'cli', subpath),
+ path.join(__dirname, '..', '..', '..', 'cli', subpath)
+ ];
+ for (const candidate of roots) {
+ try {
+ return require(candidate);
+ } catch (e) {
+ // continue
+ }
+ }
+ throw new Error('Unable to resolve CLI Bun module: ' + subpath);
+}
+
+module.exports = resolveCliModule('config/bun/snapshot.js');
diff --git a/index.js b/index.js
index acb88a2..ff061dd 100644
--- a/index.js
+++ b/index.js
@@ -28,3 +28,8 @@ exportOnDemand({
VerboseLogPlugin: () => require('./plugins/VerboseLogPlugin'),
WebOSMetaPlugin: () => require('./plugins/WebOSMetaPlugin')
});
+
+// Export Bun build helpers.
+exportOnDemand({
+ bunPlugins: () => require('./bun-plugins')
+});
diff --git a/plugins/PrerenderPlugin/FileXHR.js b/plugins/PrerenderPlugin/FileXHR.js
index b9f0cc4..8fb5c1a 100644
--- a/plugins/PrerenderPlugin/FileXHR.js
+++ b/plugins/PrerenderPlugin/FileXHR.js
@@ -1,4 +1,135 @@
const fs = require('fs');
+const path = require('path');
+
+function escapeRegExp(string) {
+ return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
+}
+
+function untransformPath(uri) {
+ return uri
+ .replace(/\\/g, '/')
+ .replace(/(^|\/)(_)($|\/)/g, (match, before, segment, after) => before + '..' + (after || ''));
+}
+
+const ILIB_URL_PREFIXES = [
+ '/node_modules/ilib',
+ '/node_modules/@enact/i18n/ilib',
+ '/node_modules/_enact/i18n/ilib',
+ 'node_modules/ilib',
+ 'node_modules/@enact/i18n/ilib',
+ 'node_modules/_enact/i18n/ilib'
+];
+
+function normalizePathSlashes(filePath) {
+ return filePath.replace(/\\/g, '/');
+}
+
+function resolveIlibReplacement() {
+ if (process.env.ILIB_FS_PATH) {
+ return normalizePathSlashes(process.env.ILIB_FS_PATH);
+ }
+
+ const basePath = normalizePathSlashes(process.env.ILIB_BASE_PATH || '');
+ if (/i18n[/\\]ilib[/\\]*$/.test(basePath)) {
+ return 'node_modules/@enact/i18n/ilib';
+ }
+
+ return 'node_modules/ilib';
+}
+
+function getIlibUrlPrefixes() {
+ const prefixes = [process.env.ILIB_BASE_PATH, ...ILIB_URL_PREFIXES].filter(Boolean).map(normalizePathSlashes);
+
+ return [...new Set(prefixes)];
+}
+
+function tryResolvePath(candidate) {
+ return fs.existsSync(candidate) ? candidate : null;
+}
+
+function resolveFromIlibPrefix(filePath, prefix, cwd) {
+ if (!prefix || !filePath.startsWith(prefix)) {
+ return null;
+ }
+
+ const suffix = filePath.slice(prefix.length).replace(/^\//, '');
+ const fsPath = process.env.ILIB_FS_PATH;
+
+ if (fsPath) {
+ const fromFs = tryResolvePath(path.join(fsPath, suffix));
+ if (fromFs) {
+ return fromFs;
+ }
+ }
+
+ const replacement = resolveIlibReplacement();
+ const relative = normalizePathSlashes(path.join(replacement, suffix));
+
+ let resolved = tryResolvePath(path.resolve(cwd, relative));
+ if (resolved) {
+ return resolved;
+ }
+
+ if (relative.includes('@enact/i18n/ilib')) {
+ resolved = tryResolvePath(path.resolve(cwd, relative.replace('@enact/i18n/ilib', 'ilib')));
+ if (resolved) {
+ return resolved;
+ }
+ }
+
+ return null;
+}
+
+function isWebRootNodeModulesPath(filePath) {
+ return /^\/node_modules\//.test(filePath);
+}
+
+function resolveFilePath(uri) {
+ const cwd = process.env.ILIB_CONTEXT || process.cwd();
+ let filePath = normalizePathSlashes(uri);
+
+ for (const prefix of getIlibUrlPrefixes()) {
+ const fromPrefix = resolveFromIlibPrefix(filePath, prefix, cwd);
+ if (fromPrefix) {
+ return fromPrefix;
+ }
+ }
+
+ if (process.env.ILIB_BASE_PATH) {
+ const replacement = resolveIlibReplacement();
+ filePath = filePath.replace(
+ new RegExp('^' + escapeRegExp(normalizePathSlashes(process.env.ILIB_BASE_PATH))),
+ replacement
+ );
+ }
+
+ filePath = untransformPath(filePath);
+
+ if (isWebRootNodeModulesPath(filePath)) {
+ const fromWebRoot = tryResolvePath(path.resolve(cwd, filePath.replace(/^\//, '')));
+ if (fromWebRoot) {
+ return fromWebRoot;
+ }
+ }
+
+ if (path.isAbsolute(filePath) && !isWebRootNodeModulesPath(filePath)) {
+ return filePath;
+ }
+
+ const resolved = path.resolve(cwd, filePath);
+ if (fs.existsSync(resolved)) {
+ return resolved;
+ }
+
+ if (filePath.includes('@enact/i18n/ilib')) {
+ const fallback = path.resolve(cwd, filePath.replace('@enact/i18n/ilib', 'ilib'));
+ if (fs.existsSync(fallback)) {
+ return fallback;
+ }
+ }
+
+ return resolved;
+}
function FileXHR() {}
@@ -14,20 +145,9 @@ FileXHR.prototype.addEventListener = function (evt, fn) {
FileXHR.prototype.send = function () {
if (this.method.toUpperCase() === 'GET' && this.uri && this.sync) {
- if (process.env.ILIB_BASE_PATH) {
- // Backward compatability for old iLib location
- if (/i18n[/\\]ilib[/\\]*$/.test(process.env.ILIB_BASE_PATH)) {
- this.uri = this.uri.replace(
- new RegExp('^' + process.env.ILIB_BASE_PATH),
- 'node_modules/@enact/i18n/ilib'
- );
- } else {
- this.uri = this.uri.replace(new RegExp('^' + process.env.ILIB_BASE_PATH), 'node_modules/ilib');
- }
- }
- const parsedURI = this.uri.replace(/\\/g, '/').replace(/^(_\/)+/g, match => match.replace(/_/g, '..'));
+ const parsedURI = resolveFilePath(this.uri);
try {
- if (!fs.existsSync(parsedURI)) throw new Error('File not found: ' + this.uri);
+ if (!fs.existsSync(parsedURI)) throw new Error('File not found: ' + parsedURI);
this.response = this.responseText = fs.readFileSync(parsedURI, {encoding: 'utf8'});
this.status = 200;
diff --git a/plugins/PrerenderPlugin/index.js b/plugins/PrerenderPlugin/index.js
index 85c6376..34ea72e 100644
--- a/plugins/PrerenderPlugin/index.js
+++ b/plugins/PrerenderPlugin/index.js
@@ -622,4 +622,136 @@ function emitAsset(compilation, name, data) {
// Usage: PrerenderPlugin.getHooks(compilation).HOOK_NAME.tapAsync('YourPluginName', () => { ... });
PrerenderPlugin.getHooks = getPrerenderPluginHooks;
+function stageBunChunk(code, opts) {
+ if (/__webpack_require__\.e\s*=/.test(code)) {
+ code = code.replace('__webpack_require__.e =', '__webpack_require__.e = function() {}; var origE =');
+ }
+ if (/function webpackAsyncContext\(req\)/.test(code)) {
+ code = code.replace(
+ 'function webpackAsyncContext(req) {',
+ 'function webpackAsyncContext(req) {\n\treturn new Promise(function() {});'
+ );
+ }
+
+ // Do not regex-replace bare window/document — that corrupts string literals
+ // (e.g. "window" → "undefined"). vdom-server-render loads the chunk in a vm
+ // context that omits those globals instead.
+ vdomServer.stage(code, opts);
+}
+
+function applyBunPostBuild(options = {}) {
+ const opts = Object.assign(
+ {
+ chunk: 'main.js',
+ locales: 'en-US',
+ mapfile: 'locale-map.json',
+ publicPath: '/',
+ screenTypes: [],
+ deep: null,
+ externals: null,
+ fontGenerator: null,
+ externalStartup: false
+ },
+ options
+ );
+ const chunkPath = path.join(opts.output, opts.chunk);
+ if (!fs.existsSync(chunkPath)) {
+ throw new Error('PrerenderPlugin: Unable to find build chunk at ' + chunkPath);
+ }
+ const code = fs.readFileSync(chunkPath, {encoding: 'utf8'});
+ const locales = parseLocales(opts.context, opts.locales);
+ const server = opts.server || path.join(opts.context, 'node_modules', 'react-dom', 'server.js');
+ const status = {prerender: [], attr: [], alias: []};
+
+ stageBunChunk(code, {chunk: opts.chunk, externals: opts.externals});
+ for (let i = 0; i < locales.length; i++) {
+ try {
+ const renderOpts = {
+ server,
+ locale: locales[i],
+ externals: opts.externals,
+ fontGenerator: opts.fontGenerator,
+ context: opts.context
+ };
+ let appHtml = vdomServer.render(renderOpts);
+ status.attr[i] = {classes: ''};
+ appHtml = appHtml.replace(
+ /(
]*class="((?!enact-locale-)[^"])*)(\senact-locale-[^"]*)"/i,
+ (match, before, s, classAttr) => {
+ status.attr[i].classes = classAttr;
+ return before + '"';
+ }
+ );
+ const index = status.prerender.indexOf(appHtml);
+ if (index === -1) {
+ status.prerender[i] = appHtml;
+ } else {
+ status.alias[i] = locales[index];
+ }
+ } catch (e) {
+ status.err = {locale: locales[i], result: e};
+ break;
+ }
+ }
+ vdomServer.unstage();
+ if (status.err) {
+ throw status.err.result;
+ }
+ if (status.alias.some(Boolean)) {
+ simplifyAliases(locales, status);
+ }
+
+ const indexPath = path.join(opts.output, 'index.html');
+ let html = fs.readFileSync(indexPath, {encoding: 'utf8'});
+ const jsAssets = opts.startupAssets || [
+ path.posix.join(opts.publicPath || '/', opts.chunk).replace(/\/{2,}/g, '/')
+ ];
+ const startupScript = templates.startup(opts.screenTypes, jsAssets);
+ html = html.replace(/type="module"/g, 'type="text/javascript"');
+ html = html.replace(
+ /<\/head>/i,
+ match => `\t\n\t${match}`
+ );
+
+ const applyToRoot = rootInjection(html);
+ for (let i = 0; i < locales.length; i++) {
+ if (!status.prerender[i] || status.alias[i]) continue;
+ const linked = Object.keys(status.alias).filter(key => status.alias[key] === locales[i]);
+ let mapping;
+ if (linked.length === 0) {
+ status.prerender[i] = status.prerender[i].replace(
+ /(
]*class="[^"]*)"/i,
+ '$1' + status.attr[i].classes + '"'
+ );
+ } else {
+ mapping = linked.reduce((m, c) => Object.assign(m, {[locales[c].toLowerCase()]: status.attr[c]}), {});
+ }
+ const appHtml = parsePrerender(status.prerender[i]);
+ const updater = templates.update(mapping, opts.deep, appHtml.prerender);
+ let localeHtml = applyToRoot(appHtml.prerender);
+ if (updater) {
+ localeHtml = localeHtml.replace(
+ /<\/body>/i,
+ match => `\t\n\t${match}`
+ );
+ }
+ if (locales.length === 1) {
+ html = localeHtml;
+ } else {
+ fs.writeFileSync(path.join(opts.output, 'index.' + locales[i] + '.html'), localeHtml, {encoding: 'utf8'});
+ }
+ }
+ fs.writeFileSync(indexPath, html, {encoding: 'utf8'});
+
+ if (opts.mapfile && locales.length > 1) {
+ const mapper = (m, c, i) =>
+ status.alias.includes(c) ? m : Object.assign(m, {[c]: `index.${status.alias[i] || c}.html`});
+ const mapping = {fallback: 'index.html', locales: locales.reduce(mapper, {})};
+ fs.writeFileSync(path.join(opts.output, opts.mapfile), JSON.stringify(mapping, null, '\t'), {encoding: 'utf8'});
+ }
+}
+
+PrerenderPlugin.applyBunPostBuild = applyBunPostBuild;
+PrerenderPlugin.parseLocales = parseLocales;
+
module.exports = PrerenderPlugin;
diff --git a/plugins/PrerenderPlugin/vdom-server-render.js b/plugins/PrerenderPlugin/vdom-server-render.js
index d79d0f0..c43aefa 100644
--- a/plugins/PrerenderPlugin/vdom-server-render.js
+++ b/plugins/PrerenderPlugin/vdom-server-render.js
@@ -7,6 +7,8 @@
const fs = require('fs');
const path = require('path');
+const vm = require('vm');
+const Module = require('module');
const requireUncached = require('import-fresh');
const reroute = require('mock-require');
const FileXHR = require('./FileXHR');
@@ -16,17 +18,189 @@ require('console.mute');
let chunkTarget;
let prerenderCache;
-import('find-cache-directory').then(({default: findCacheDirectory}) => {
- prerenderCache = path.join(
- findCacheDirectory({
- name: 'enact-dev',
- create: true
- }),
- 'prerender'
- );
+const ILIB_LOCALEMATCH_GLOBAL = '__ENACT_PRERENDER_LOCALEMATCH__';
+const ILIB_DATA_INIT_PATTERN =
+ /cache: \{\} \}, typeof module2 != "undefined" && \(module2\.exports = ilib, module2\.exports\.ilib = ilib\)/g;
+const ILIB_DATA_INIT_SEED =
+ 'cache: {} }, global.' +
+ ILIB_LOCALEMATCH_GLOBAL +
+ '&&(ilib.data.localematch=global.' +
+ ILIB_LOCALEMATCH_GLOBAL +
+ '), typeof module2 != "undefined" && (module2.exports = ilib, module2.exports.ilib = ilib)';
- if (!fs.existsSync(prerenderCache)) fs.mkdirSync(prerenderCache);
-});
+/**
+ * Load a staged chunk in a vm context that shares Node require / prerender
+ * globals but intentionally omits window/document/self so browser-only paths
+ * see typeof window === 'undefined' without regex-rewriting the bundle text.
+ */
+function loadStagedChunk(chunkPath) {
+ const code = fs.readFileSync(chunkPath, {encoding: 'utf8'});
+ const moduleObject = {exports: {}};
+ const localRequire = Module.createRequire(chunkPath);
+ const context = {
+ module: moduleObject,
+ exports: moduleObject.exports,
+ require: localRequire,
+ __filename: chunkPath,
+ __dirname: path.dirname(chunkPath),
+ console,
+ process,
+ Buffer,
+ setTimeout,
+ clearTimeout,
+ setInterval,
+ clearInterval,
+ setImmediate,
+ clearImmediate,
+ queueMicrotask,
+ URL,
+ URLSearchParams,
+ Promise,
+ Object,
+ Array,
+ String,
+ Number,
+ Boolean,
+ Symbol,
+ Math,
+ Date,
+ RegExp,
+ Error,
+ TypeError,
+ RangeError,
+ SyntaxError,
+ JSON,
+ Map,
+ Set,
+ WeakMap,
+ WeakSet,
+ Proxy,
+ Reflect,
+ parseInt,
+ parseFloat,
+ isNaN,
+ isFinite,
+ encodeURIComponent,
+ decodeURIComponent,
+ encodeURI,
+ decodeURI,
+ // Prerender-shared state (also mirrored onto context.global below)
+ React: global.React,
+ enact_framework: global.enact_framework,
+ enactHooks: global.enactHooks,
+ ilib: global.ilib,
+ XMLHttpRequest: global.XMLHttpRequest,
+ skipPolyfills: global.skipPolyfills
+ };
+ if (global[ILIB_LOCALEMATCH_GLOBAL] !== undefined) {
+ context[ILIB_LOCALEMATCH_GLOBAL] = global[ILIB_LOCALEMATCH_GLOBAL];
+ }
+ // No window / document / self — keeps DOM startup paths inert.
+ context.global = context;
+ context.globalThis = context;
+
+ vm.createContext(context);
+ vm.runInContext(code, context, {
+ filename: chunkPath,
+ displayErrors: true
+ });
+
+ return moduleObject.exports && moduleObject.exports.default !== undefined
+ ? moduleObject.exports
+ : context.module.exports;
+}
+
+function readLocaleMatchData() {
+ const fsPath = process.env.ILIB_FS_PATH || process.env.ILIB_BASE_PATH;
+ if (!fsPath) return null;
+
+ const localeMatchPath = path.join(fsPath, 'locale', 'localematch.json');
+ if (!fs.existsSync(localeMatchPath)) return null;
+
+ try {
+ const localematch = JSON.parse(fs.readFileSync(localeMatchPath, {encoding: 'utf8'}));
+ return localematch && localematch.likelyLocales ? localematch : null;
+ } catch (_e) {
+ return null;
+ }
+}
+
+function resetIlibGlobalState() {
+ // ilib.js uses `var ilib = ilib || {}`, so repeated prerender passes share one global
+ // singleton. After many locale renders, cached localematch data can become incomplete.
+ if (global.ilib) {
+ if (global.ilib.data && typeof global.ilib.clearCache === 'function') {
+ global.ilib.clearCache();
+ }
+ delete global.ilib;
+ }
+}
+
+function seedIlibLocaleMatch() {
+ const localematch = readLocaleMatchData();
+ if (!localematch) return;
+
+ global.ilib = global.ilib || {};
+ global.ilib.data = global.ilib.data || {};
+ global.ilib.data.localematch = localematch;
+ if (global.ilib._load) {
+ global.ilib._load._cacheValidated = false;
+ }
+}
+
+function injectBundledIlibLocaleMatchSeed(code) {
+ return code.replace(ILIB_DATA_INIT_PATTERN, ILIB_DATA_INIT_SEED);
+}
+
+function resolveFromContext(moduleName, context) {
+ if (!context) {
+ return require.resolve(moduleName);
+ }
+ return require.resolve(moduleName, {paths: [path.join(context, 'node_modules')]});
+}
+
+function clearPrerenderModules(serverPath) {
+ const chunkPath = chunkTarget ? path.resolve(chunkTarget) : null;
+ const serverDir = serverPath ? path.dirname(path.resolve(serverPath)) : null;
+
+ Object.keys(require.cache)
+ .filter(c => {
+ if (chunkPath && path.resolve(c) === chunkPath) return true;
+ if (serverDir && c.startsWith(serverDir)) return true;
+ return /[\\/]node_modules[\\/](react(-dom)?|ilib|@enact)([\\/]|$)/.test(c);
+ })
+ .forEach(c => delete require.cache[c]);
+
+ try {
+ reroute.stop('react');
+ } catch (_e) {
+ // ignore if react was not rerouted yet
+ }
+
+ delete global.React;
+ delete global.enact_framework;
+ delete global.enactHooks;
+}
+
+function getPrerenderCache() {
+ if (prerenderCache) return prerenderCache;
+
+ try {
+ const findCacheDirectory = require('find-cache-directory');
+ prerenderCache = path.join(
+ findCacheDirectory({
+ name: 'enact-dev',
+ create: true
+ }),
+ 'prerender'
+ );
+ } catch (e) {
+ prerenderCache = path.join(process.cwd(), 'node_modules', '.cache', 'enact-dev', 'prerender');
+ }
+
+ fs.mkdirSync(prerenderCache, {recursive: true});
+ return prerenderCache;
+}
// Skip using the polyfills embedded within the bundle and instead use a local core-js,
// since the bundle's target may differ in compatibility from the active Node process
@@ -57,7 +231,8 @@ module.exports = {
'require("' + path.resolve(path.join(opts.externals, 'enact.js')) + '")'
);
}
- chunkTarget = path.join(prerenderCache, opts.chunk);
+ code = injectBundledIlibLocaleMatchSeed(code);
+ chunkTarget = path.join(getPrerenderCache(), opts.chunk);
fs.writeFileSync(chunkTarget, code, {encoding: 'utf8'});
},
@@ -86,7 +261,7 @@ module.exports = {
console.mute();
try {
- const generator = require(path.resolve(opts.fontGenerator));
+ const generator = requireUncached(path.resolve(opts.fontGenerator));
const locale = opts.locale || 'en-US';
style = generator(locale);
if (generator.fontOverrideGenerator) style += generator.fontOverrideGenerator(locale);
@@ -102,26 +277,63 @@ module.exports = {
global.process.env.LANG = opts.locale;
+ clearPrerenderModules(opts.server);
+
+ if (opts.locale) {
+ resetIlibGlobalState();
+ seedIlibLocaleMatch();
+ }
+
if (opts.externals) {
- // Ensure locale switching support is loaded globally with external framework usage.
- const framework = requireUncached(path.resolve(path.join(opts.externals, 'enact.js')));
+ const frameworkPath = path.resolve(path.join(opts.externals, 'enact.js'));
+ let framework = requireUncached(frameworkPath);
+ if (framework && typeof framework.default === 'function') {
+ framework = framework.default;
+ }
+ if (typeof framework !== 'function') {
+ const previousFramework = global.enact_framework;
+ delete global.enact_framework;
+ requireUncached(frameworkPath);
+ framework = global.enact_framework;
+ if (previousFramework !== undefined) {
+ global.enact_framework = previousFramework;
+ } else {
+ delete global.enact_framework;
+ }
+ }
+ if (typeof framework !== 'function') {
+ throw new Error('External Enact framework must export enact_framework(id).');
+ }
+ global.enact_framework = framework;
global.React = framework('react');
} else {
- delete global.React;
+ global.React = requireUncached(resolveFromContext('react', opts.context));
}
- const chunk = requireUncached(path.resolve(chunkTarget));
+ reroute('react', global.React);
- // Clear any server-related children modules from cache
- Object.keys(require.cache)
- .filter(c => c.startsWith(path.dirname(opts.server)))
- .forEach(c => delete require.cache[c]);
+ let localeMatchSeed;
+ if (opts.locale) {
+ localeMatchSeed = readLocaleMatchData();
+ if (localeMatchSeed) {
+ global[ILIB_LOCALEMATCH_GLOBAL] = localeMatchSeed;
+ }
+ }
- // Use the specified server, optionally with exposed React, and generate HTML string
- if (global.React) reroute('react', global.React);
- const server = requireUncached(opts.server);
+ const chunk = loadStagedChunk(path.resolve(chunkTarget));
+
+ if (localeMatchSeed) {
+ delete global[ILIB_LOCALEMATCH_GLOBAL];
+ }
+ let server;
+ if (opts.externals && global.enact_framework) {
+ const domServer = global.enact_framework('react-dom/server');
+ server = domServer.default || domServer;
+ } else {
+ server = requireUncached(opts.server);
+ }
rendered = server.renderToString(chunk['default'] || chunk);
- if (global.React) reroute.stop('react');
+ reroute.stop('react');
if (style) {
rendered = '\n' + style + '\n' + rendered;