@omnia/tooling-vue
Version:
Used to bundle and serve manifests web component that build on Vue framework.
366 lines (336 loc) • 17.2 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.registerHmrMiddleware = void 0;
const tslib_1 = require("tslib");
const fs_1 = tslib_1.__importDefault(require("fs"));
const path_1 = tslib_1.__importDefault(require("path"));
const webpack_1 = require("webpack");
const fx_models_1 = require("@omnia/fx-models");
const hmr_1 = require("../hmr");
const utils_1 = require("../hmr/utils");
const $ = tslib_1.__importStar(require("../../variables"));
const bundler = tslib_1.__importStar(require("../../tasks/bundle"));
const graph_1 = require("../hmr/graph");
const shared_1 = require("./shared");
let preBundled = false;
function registerHmrMiddleware(server) {
$.tooling.core.registerServeTask({
stage: $.tooling.core.TaskStage.AfterScanManifests,
order: 3,
task: async function (entries) {
const serviceId = $.tooling.composer.getServiceId();
$.tooling.log("HMR Middleware running...");
hmr_1.entriesResolver.resolveEntries(entries);
$.tooling.log("Building module dependency graphs...");
const manifests = await (0, graph_1.buildFileGraphs)(entries);
$.tooling.log("Done - Building module dependency graphs");
return ensureManifestInfo(entries).then(preBundleIfNeeded).then(() => {
bundler.processManifestGenerated(entries, $.tooling.composer.OmniaOutput.OutputBundlePath);
Object.keys(manifests).forEach(resourceId => {
manifests[resourceId].dependingOnManifests.forEach(dependingOnManifest => {
if (serviceId == dependingOnManifest.serviceId) {
bundler.addDependency(resourceId, dependingOnManifest.resourceId, null);
}
else {
bundler.addDependency(resourceId, dependingOnManifest.resourceId, dependingOnManifest.serviceId);
}
});
});
(0, hmr_1.clearManifestCollection)();
});
}
});
const assetsDir = $.tooling.composer.getAssetsDir();
const host = `https://localhost:${server.config.server.port}`;
server.middlewares.use(utils_1.pathUtils.OMNIA_BUNDLE_REQUEST, async (req, res, next) => {
const { resourceId, bundleFileExtension, fromWorker } = utils_1.pathUtils.parseOmniaBundlePath(req.url);
if (resourceId == shared_1.LocalizationId) {
next();
return;
}
const manifest = (0, hmr_1.getManifest)(resourceId);
res.setHeader('Access-Control-Allow-Headers', ['omnia-nextgen-ui-tenant', 'omnia-nextgen-ui-trial', 'omniatokenkey']);
if (bundleFileExtension == 'js') {
res.setHeader('Content-Type', 'application/x-javascript');
}
else if (bundleFileExtension == 'css') {
res.setHeader('Content-Type', 'text/css');
}
else {
console.error(`Unsupported bundle file extension: ${bundleFileExtension}. Current resource id = ${resourceId}`);
}
if (!manifest) {
const message = `Cannot resolve manifest (resourceId = ${resourceId})`;
res.statusCode = 500;
res.statusMessage = message;
console.error(message);
}
else if (resourceId == fx_models_1.OmniaResourceManifests.Vendor.toString() ||
resourceId == fx_models_1.OmniaResourceManifests.HMR.toString() ||
resourceId == fx_models_1.OmniaResourceManifests.FxWorkers.toString()) {
const serviceId = $.tooling.composer.getServiceId();
const bundleDirPath = utils_1.envUtils.getBundleOutputDirPath();
const bundleFileName = manifest.resourceName ? `${manifest.resourceName}_${resourceId}.${bundleFileExtension}` : `${resourceId}.${bundleFileExtension}`;
const bundlePath = path_1.default.join(bundleDirPath, bundleFileName);
let script = await fs_1.default.promises.readFile(bundlePath, 'utf8');
if ($.composers.LoadableManifestRegistry.isDefineWithNoDependency(resourceId)) {
script = script + '\n\n' + `omniaLoader['${serviceId}']['${resourceId}']();`;
}
res.write(script);
}
else if (manifest.manifestType == fx_models_1.ClientManifestTypes.Component || manifest.manifestType == fx_models_1.ClientManifestTypes.Resource) {
const script = await buildManifestResolveScript(host, assetsDir, manifest, bundleFileExtension, false, fromWorker);
res.write(script);
}
else if (manifest.manifestType == fx_models_1.ClientManifestTypes.ManifestGroup) {
const script = await buildGroupManifestResolveScript(host, assetsDir, manifest, bundleFileExtension, fromWorker);
res.write(script);
}
else {
const message = `Unexpected error when resolving manifest (resourceId = ${resourceId})`;
res.statusCode = 500;
res.statusMessage = message;
console.error(message);
}
res.end();
});
server.middlewares.use(utils_1.pathUtils.HMR_ESM_REQUEST, async (req, res, next) => {
res.setHeader('Access-Control-Allow-Headers', ['omnia-nextgen-ui-tenant', 'omnia-nextgen-ui-trial', 'omniatokenkey']);
res.setHeader('Content-Type', 'application/x-javascript');
const { resourceId, fromWorker } = utils_1.pathUtils.parseHmrEsmPath(req.url);
const manifest = (0, hmr_1.getManifest)(resourceId);
if (!manifest) {
const message = `Cannot resolve manifest (resourceId = ${resourceId})`;
res.statusCode = 500;
res.statusMessage = message;
console.error(message);
}
const script = await createEsmImportScript(manifest, fromWorker);
res.end(script);
});
server.middlewares.use(utils_1.pathUtils.HMR_DYNAMIC_BUNDLE_REQUEST, async (req, res, next) => {
res.setHeader('Access-Control-Allow-Headers', ['omnia-nextgen-ui-tenant', 'omnia-nextgen-ui-trial', 'omniatokenkey']);
res.setHeader('Content-Type', 'application/x-javascript');
const { resourceId, fromWorker } = utils_1.pathUtils.parseHmrDynamicBundlePath(req.url);
const bundleDirPath = utils_1.envUtils.getBundleOutputDirPath();
const bundleFileName = `dynamicbundle_${resourceId}.js`;
const bundlePath = path_1.default.join(bundleDirPath, bundleFileName);
let script = await fs_1.default.promises.readFile(bundlePath, 'utf8');
// webpack bundled as commonjs so we need to make this as es module
script = script + '\n\n' + `//Empty export to make this as es module\nexport {}`;
res.end(script);
});
}
exports.registerHmrMiddleware = registerHmrMiddleware;
async function preBundleIfNeeded(entries) {
if (preBundled) {
return;
}
preBundled = true;
const preBundleEntries = await hmr_1.entriesResolver.getPreBundleEntries();
if (Object.keys(preBundleEntries).length == 0) {
return Promise.resolve();
}
$.tooling.log("Pre-Bundling...");
return new Promise(function (resolve, reject) {
const configs = utils_1.webpackUtils.createWebpackConfig(preBundleEntries, 'prebundle');
const compiler = (0, webpack_1.webpack)(configs);
compiler.run((err) => {
if (err) {
$.tooling.log(err);
reject();
return;
}
$.tooling.log("Pre-Bundle done");
resolve(entries);
});
});
}
function ensureManifestInfo(entries) {
const setDummyVersion = (manifestId) => {
const dummyHash = 'hmr';
const manifestInfo = $.composers.LoadableManifestRegistry.getRegisteredManifest(manifestId);
if (manifestInfo != null) {
$.composers.LoadableManifestRegistry.addManifestVersion(manifestId, $.enums.BundleTargetTypes.Javascript, dummyHash);
$.composers.LoadableManifestRegistry.addManifestBundleType(manifestId, $.enums.BundleTargetTypes.Javascript);
}
};
Object.keys(entries).forEach(key => {
const manifestId = $.tooling.utils.getGuidValue(key);
if (manifestId) {
setDummyVersion(manifestId);
}
});
const manifestGroupRegistry = $.composers.ManifestGroupRegistry;
const groupRegistrations = manifestGroupRegistry.getRegistrations();
if (groupRegistrations.length > 0) {
$.tooling.log("Found [" + groupRegistrations.length + "] group manifests", $.tooling.LogTypes.HeadLine);
groupRegistrations.forEach(reg => {
const manifestIds = reg.manifestIdsInGroup;
const targetManifestId = reg.resourceId;
if (!manifestIds || !targetManifestId || manifestIds.length == 0) {
return;
}
setDummyVersion(targetManifestId);
});
}
return Promise.resolve(entries);
}
async function createEsmImportScript(manifest, fromWorker) {
const entries = await hmr_1.entriesResolver.getEntries();
const key = utils_1.manifestUtils.getEntryKeyFromManifest(manifest);
const entryPaths = entries[key].map(p => p.substr(1));
const importModulesString = entryPaths.reduce((content, entryPath) => {
if (utils_1.pathUtils.isSourceCodePath(entryPath)) {
const timestamp = (0, hmr_1.getModuleTimestamp)(entryPath);
const urlImport = utils_1.pathUtils.modify(entryPath)
.appendTimestamp(timestamp)
.appendWorkerIdentifier(fromWorker)
.getValue();
return content + '\n' + `import '${urlImport}';`;
}
else if (utils_1.pathUtils.isNodeModulePath(entryPath) || utils_1.pathUtils.isPublicDirPath(entryPath)) {
// node modules & public imports are pre-bundled so we dont need to load
return content;
}
console.warn('Unhandled entry path: ' + entryPath);
return content;
}, '').trim();
return importModulesString;
}
async function buildGroupManifestResolveScript(host, assetDir, groupManifest, requestedFileExtension, fromWorker) {
const serviceId = $.tooling.composer.getServiceId();
const resourceId = groupManifest.resourceId;
const manifestScriptPromises = groupManifest.manifestIdsInGroup.map(manifestId => {
const manifest = (0, hmr_1.getManifest)(manifestId);
return buildManifestResolveScript(host, assetDir, manifest, requestedFileExtension, true, fromWorker);
});
const manifestScripts = await Promise.all(manifestScriptPromises);
const groupManifestScript = manifestScripts.reduce((content, script, index) => {
return content + '\n' + `
omniaWebpackJsonp['bb000000-0000-bbbb-0000-0000000000bb']['a2892051-fd9f-4056-ae8d-30d16d48417d']('06e712d2-9897-4891-9353-148547efe61c')
.ManifestResourceLoader.registerWebComponentFromGroupBundle('${serviceId}', '${groupManifest.manifestIdsInGroup[index]}', '${resourceId}', function () {
${script}
});`;
}, '').trim();
const template = `
if (typeof omniaLoader === 'undefined'){
globalThis['omniaLoader'] = {};
}
omniaLoader['${serviceId}'] = omniaLoader['${serviceId}'] || {};
if (omniaLoader['${serviceId}']['${resourceId}']) {
throw new Error("Error, already loaded manifest ${resourceId} with service id ${serviceId}");
}
let groupManifestLoaderTriggered = false;
omniaLoader['${serviceId}']['${resourceId}'] = function () {
if (groupManifestLoaderTriggered) {
return;
}
groupManifestLoaderTriggered = true;
${groupManifestScript}
}
`;
return template.trim();
}
async function buildManifestResolveScript(host, assetDir, manifest, requestedFileExtension, forGroupManifest, fromWorker) {
const serviceId = $.tooling.composer.getServiceId();
const resourceId = manifest.resourceId;
const entries = await hmr_1.entriesResolver.getEntries();
const key = utils_1.manifestUtils.getEntryKeyFromManifest(manifest);
const hasPreBundle = entries[key].some(p => p.startsWith('./node_modules') || p.startsWith('./' + assetDir));
let preBundleContent = '';
if (hasPreBundle) {
const preBundleFileNames = manifest.availableBundleTargetTypes.map(fileExtension => key + "." + fileExtension);
const preBundleFilePaths = await (0, hmr_1.validatePreBundles)(preBundleFileNames);
const preBundleAvailable = preBundleFilePaths.some(filePath => filePath.endsWith(requestedFileExtension));
if (!preBundleAvailable) {
// node_modules and public css will be pre-bundled
const hasPreBundleCss = entries[key].some(p => (p.startsWith('./node_modules') || p.startsWith('./' + assetDir)) && p.endsWith('.css'));
if (hasPreBundleCss) {
throw new utils_1.ErrorHMR(`Pre-Bundle file '${requestedFileExtension}' not found for resource ${resourceId}`);
}
// source code css will be imported directly via esm so we will load css as empty in case manifest resource loader requests
return '';
}
const preBundlePath = preBundleFilePaths.find(p => p.endsWith(`.${requestedFileExtension}`));
preBundleContent = await fs_1.default.promises.readFile(preBundlePath, { encoding: 'utf8' });
}
if (requestedFileExtension == 'css') {
return preBundleContent;
}
const template = `
if (typeof omniaLoader === 'undefined'){
globalThis['omniaLoader'] = {};
}
omniaLoader['${serviceId}'] = omniaLoader['${serviceId}'] || {};
if (omniaLoader['${serviceId}']['${resourceId}']) {
throw new Error("Error, already loaded manifest ${resourceId} with service id ${serviceId}");
}
${fromWorker ? `// Web Worker workaround to load ES module\nif (typeof __shimport__ === 'undefined') { importScripts('${host}/node_modules/shimport/index.js'); }` : ""}
let preBundleLoader;
let resolveManifest;
let triggered = false;
const manifestResolvePromise = new Promise(function (resolve) {
resolveManifest = resolve;
});
omniaLoader['${serviceId}']['${resourceId}'] = function (preBundle) {
if (preBundle && !preBundleLoader) {
preBundleLoader = preBundle;
return;
}
if (triggered) {
return manifestResolvePromise;
}
triggered = true;
// webpack intergration
if (typeof omniaWebpackJsonp === 'undefined') {
globalThis['omniaWebpackJsonp'] = {};
}
omniaWebpackJsonp['${serviceId}'] = omniaWebpackJsonp['${serviceId}'] || {};
if (omniaWebpackJsonp['${serviceId}']['${resourceId}']) {
throw new Error("Error, already loaded manifest ${resourceId} with service id ${serviceId}");
}
// hmr module exports
if (typeof ${utils_1.transformUtils.HMR_MODULE_EXPORTS_VARIABLE} === 'undefined') {
globalThis['${utils_1.transformUtils.HMR_MODULE_EXPORTS_VARIABLE}'] = {};
}
${utils_1.transformUtils.HMR_MODULE_EXPORTS_VARIABLE}['${serviceId}'] = ${utils_1.transformUtils.HMR_MODULE_EXPORTS_VARIABLE}['${serviceId}'] || {};
${utils_1.transformUtils.HMR_MODULE_EXPORTS_VARIABLE}['${serviceId}']['${resourceId}'] = ${utils_1.transformUtils.HMR_MODULE_EXPORTS_VARIABLE}['${serviceId}']['${resourceId}'] || {};
// pre-bundle exports
let preBundleWebpackRequire;
if (preBundleLoader) {
preBundleLoader();
}
function require(moduleId) {
const moduleExports = ${utils_1.transformUtils.HMR_MODULE_EXPORTS_VARIABLE}['${serviceId}']['${resourceId}'][moduleId];
if (moduleExports) {
return moduleExports;
}
if (preBundleWebpackRequire) {
return preBundleWebpackRequire(moduleId);
}
throw new Error('Could not found module id: ' + moduleId + ' from manifest ${resourceId} with service id ${serviceId}');
}
${fromWorker ?
`const { href } = new URL('${host}${utils_1.pathUtils.HMR_ESM_REQUEST}/${resourceId}${fromWorker ? `?${utils_1.pathUtils.WORKER_IDENTIFIER}` : ''}', location.href);
__shimport__.load(href).then(function () {
if (omniaWebpackJsonp['${serviceId}']['${resourceId}']) {
preBundleWebpackRequire = omniaWebpackJsonp['${serviceId}']['${resourceId}'];
}
omniaWebpackJsonp['${serviceId}']['${resourceId}'] = require;
resolveManifest();
});` :
`import('${host}${utils_1.pathUtils.HMR_ESM_REQUEST}/${resourceId}${fromWorker ? `?${utils_1.pathUtils.WORKER_IDENTIFIER}` : ''}').then(function () {
if (omniaWebpackJsonp['${serviceId}']['${resourceId}']) {
preBundleWebpackRequire = omniaWebpackJsonp['${serviceId}']['${resourceId}'];
}
omniaWebpackJsonp['${serviceId}']['${resourceId}'] = require;
resolveManifest();
});`}
return manifestResolvePromise;
}
${preBundleContent}
${forGroupManifest ? 'return manifestResolvePromise;' : `${$.composers.LoadableManifestRegistry.isDefineWithNoDependency(resourceId) ? `omniaLoader['${serviceId}']['${resourceId}']();` : ''}`}
`;
return template.trim();
}