UNPKG

@omnia/tooling-vue

Version:

Used to bundle and serve manifests web component that build on Vue framework.

366 lines (336 loc) • 17.2 kB
"use strict"; 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(); }