@omnia/tooling-vue
Version:
Used to bundle and serve manifests web component that build on Vue framework.
340 lines (339 loc) • 13.4 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildFileGraph = exports.buildFileGraphs = exports.toModuleId = exports.toFileGraphId = exports.getFileGraph = void 0;
const tslib_1 = require("tslib");
const fs_1 = tslib_1.__importDefault(require("fs"));
const path_1 = tslib_1.__importDefault(require("path"));
const vite_1 = require("vite");
const fx_models_1 = require("@omnia/fx-models");
const utils_1 = require("./utils");
const manifest_1 = require("./manifest");
const vueJsx_1 = require("./vueJsx");
const $ = tslib_1.__importStar(require("../../variables"));
let fileGraphs = {};
let manifests = {};
const initialManifests = [
fx_models_1.OmniaResourceManifests.Vendor.toString(),
fx_models_1.OmniaResourceManifests.FxCore.toString(),
fx_models_1.OmniaResourceManifests.FxWorkers.toString()
];
const esbuildTransformOptions = {
target: 'es2022',
jsx: 'preserve',
sourcemap: false,
legalComments: 'inline'
};
function getFileGraph(unknownId) {
const id = toFileGraphId(unknownId);
return fileGraphs[id];
}
exports.getFileGraph = getFileGraph;
function toFileGraphId(unknownId) {
let id = unknownId;
if (utils_1.pathUtils.isTsPath(id)) {
id = utils_1.pathUtils.resolveTsPath(id);
}
if (path_1.default.isAbsolute(id)) {
return '.' + (0, vite_1.normalizePath)(id.replace((0, vite_1.normalizePath)(utils_1.envUtils.getRootDirPath()), ''));
}
if (id.startsWith('/')) {
return '.' + id;
}
return id;
}
exports.toFileGraphId = toFileGraphId;
function toModuleId(unknownId) {
let id = unknownId;
if (utils_1.pathUtils.isTsPath(id)) {
id = utils_1.pathUtils.resolveTsPath(id);
}
if (path_1.default.isAbsolute(id)) {
return (0, vite_1.normalizePath)(id.replace((0, vite_1.normalizePath)(utils_1.envUtils.getRootDirPath()), ''));
}
if (id.startsWith('./')) {
return id.substring(1);
}
return id;
}
exports.toModuleId = toModuleId;
async function buildFileGraphs(entries) {
fileGraphs = {};
manifests = {};
const graph = {};
// external manifests
const omniaPackageDependencies = utils_1.manifestUtils.getExternalManifestReferences().slice()
.filter(packageManifest => packageManifest.isVendor == false)
.map(packageManifest => {
const exportModules = Object.keys(packageManifest.content)
.filter(filePath => utils_1.pathUtils.isNodeModulePath(filePath))
.map(filePath => filePath.endsWith('index.js') ?
filePath.substr(0, filePath.lastIndexOf('/')).replace('./node_modules/', '') :
filePath.replace('./node_modules/', '').replace('.js', ''));
// fix @omnia/fx/models
if (exportModules.indexOf('@omnia/fx-models') > -1) {
exportModules.push('@omnia/fx/models');
}
return {
serviceId: packageManifest.serviceId,
resourceId: packageManifest.resourceId,
exportModules: exportModules
};
});
// pre-bundle manifests
await buildPreBundledGraphs();
// local manifests
await Object.keys(entries).reduce(async (prevPromise, entryName) => {
await prevPromise;
const parts = entryName.split('_');
const resourceId = parts.length > 1 ? parts[1] : parts[0];
const entryPaths = entries[entryName].filter(entryFile => utils_1.pathUtils.isSourceCodePath(entryFile));
const dependencies = entries[entryName].slice();
const buildDependencyGraphPromises = entryPaths.reduce(async (prevSubPromise, entryFile) => {
await prevSubPromise;
return await buildFileGraphRecursive(entryFile, dependencies, true, resourceId);
}, Promise.resolve());
await buildDependencyGraphPromises;
graph[entryName] = dependencies;
manifests[resourceId] = {
entryName: entryName,
entryPaths: entryPaths,
dependingOnManifests: [],
};
}, Promise.resolve());
const runtimeCodeGraph = graph;
// skip empty files
Object.keys(runtimeCodeGraph).forEach(entryName => {
runtimeCodeGraph[entryName] = runtimeCodeGraph[entryName].filter(fileGraphId => {
const sourceFile = fileGraphs[fileGraphId];
if (sourceFile) {
return !sourceFile.js || !sourceFile.js.empty;
}
return true;
});
});
// add manifest dependency with each others
Object.keys(manifests).forEach((resourceId, _, allResourceIds) => {
const manifest = manifests[resourceId];
const depFilePaths = runtimeCodeGraph[manifest.entryName];
if (initialManifests.indexOf(resourceId) > -1) {
return;
}
const internalManifests = allResourceIds.filter(depResourceId => {
const depedingOnManifest = manifests[depResourceId];
return resourceId != depResourceId && depedingOnManifest.entryPaths.some(entryPath => depFilePaths.indexOf(entryPath) > -1);
}).map(depResourceId => ({
resourceId: depResourceId,
serviceId: $.tooling.composer.getServiceId()
}));
const externalManifests = omniaPackageDependencies.filter(omniaPackageDependency => {
return resourceId != omniaPackageDependency.resourceId && omniaPackageDependency.exportModules.some(modulePath => depFilePaths.indexOf(modulePath) > -1);
}).map(omniaPackageDependency => ({
resourceId: omniaPackageDependency.resourceId,
serviceId: omniaPackageDependency.serviceId
}));
manifest.dependingOnManifests = [
...internalManifests,
...externalManifests
];
});
// set resource id for each files
Object.keys(fileGraphs).forEach(fileGraphId => {
const fileGraph = fileGraphs[fileGraphId];
setResourceIdForFileGraph(fileGraph);
});
return manifests;
}
exports.buildFileGraphs = buildFileGraphs;
async function buildFileGraph(unknownId, code) {
const id = toFileGraphId(unknownId);
const fileGraph = ensureFileGraph(id, false, undefined);
if (!fileGraph.js) {
return { fileGraph, code };
}
fileGraph.js.scanned = true;
const esbuildTransformResult = await (0, vite_1.transformWithEsbuild)(code, id, esbuildTransformOptions);
code = esbuildTransformResult.code;
// d.ts or interface only
if (!esbuildTransformResult.code) {
fileGraph.js.empty = true;
return { fileGraph, code, esbuildTransformResult };
}
if (id.endsWith('.tsx')) {
code = await (0, vueJsx_1.transformVueJsx)(code, id);
}
fileGraph.js.metadata = utils_1.moduleAnalysis.analyze(code, id);
ensureDependencies(id, fileGraph.js.metadata);
return { fileGraph, code, esbuildTransformResult };
}
exports.buildFileGraph = buildFileGraph;
async function buildFileGraphRecursive(id, manifestDependencies, entry, resourceId) {
const fileGraph = ensureFileGraph(id, entry, resourceId);
if (!fileGraph.js) {
return;
}
if (fileGraph.js.scanned) {
if (fileGraph.js.empty) {
return;
}
return addManifestDependencies(fileGraph, manifestDependencies, resourceId).reduce(async (prevPromise, depFileGraphId) => {
await prevPromise;
return await buildFileGraphRecursive(depFileGraphId, manifestDependencies, false, resourceId);
}, Promise.resolve());
}
const content = fs_1.default.readFileSync(id, 'utf8');
const esbuildTransformResult = await (0, vite_1.transformWithEsbuild)(content, id, esbuildTransformOptions);
fileGraph.js.scanned = true;
// d.ts or interface only
if (!esbuildTransformResult.code) {
fileGraph.js.empty = true;
return;
}
fileGraph.js.metadata = utils_1.moduleAnalysis.analyze(esbuildTransformResult.code, id);
ensureDependencies(id, fileGraph.js.metadata);
return addManifestDependencies(fileGraph, manifestDependencies, resourceId).reduce(async (prevPromise, depFileGraphId) => {
await prevPromise;
return await buildFileGraphRecursive(depFileGraphId, manifestDependencies, false, resourceId);
}, Promise.resolve());
}
async function buildPreBundledGraphs() {
const preBundleEntries = await manifest_1.entriesResolver.getPreBundleEntries();
Object.keys(preBundleEntries).forEach(key => {
const [resourceName, resourceId] = key.split('_');
preBundleEntries[key].forEach(id => {
if (fileGraphs[id] && fileGraphs[id].preBundled) {
return;
}
fileGraphs[id] = initFileGraph(id, true, true);
fileGraphs[id].resourceId = resourceId;
fileGraphs[id].preBundled = true;
});
});
}
function setResourceIdForFileGraph(fileGraph) {
// resource Id already set, this is entry file
if (!!fileGraph.resourceId) {
return;
}
// only one manifest connected to this file => the file belongs to this manifest
if (fileGraph.connectedResourceIds.length == 1) {
fileGraph.resourceId = fileGraph.connectedResourceIds[0];
fileGraph.connectedResourceIds = [];
return;
}
fileGraph.connectedResourceIds = [];
// vendor file so skip it
if (fileGraph.bareImport) {
return;
}
// more than one manifest connencted to this file => priority exporters
if (fileGraph.exporters.length > 0) {
fileGraph.resourceId = resolveResourceIdFromDependency(fileGraph.exporters[0]);
}
// if exporters has no value then check importers
if (fileGraph.importers.length > 0) {
fileGraph.resourceId = resolveResourceIdFromDependency(fileGraph.importers[0]);
}
}
function resolveResourceIdFromDependency(id) {
const fileGraph = fileGraphs[id];
if (!!fileGraph.resourceId) {
return fileGraph.resourceId;
}
setResourceIdForFileGraph(fileGraph);
return fileGraph.resourceId;
}
function addManifestDependencies(fileGraph, manifestDependencies, resourceId) {
const fileDependencies = [...fileGraph.js.metadata.importPaths, ...fileGraph.js.metadata.exportPaths];
const newManifestDependencies = fileDependencies.filter(filePath => manifestDependencies.indexOf(filePath) == -1);
if (newManifestDependencies.length > 0) {
manifestDependencies.push(...newManifestDependencies);
}
const unscannedFiles = [];
newManifestDependencies.forEach(filePath => {
const depFileGraph = ensureFileGraph(filePath, false, resourceId);
if (depFileGraph.bareImport || !depFileGraph.js || (depFileGraph.js.scanned && depFileGraph.js.empty)) {
return;
}
if (depFileGraph.js.scanned) {
unscannedFiles.push(...addManifestDependencies(depFileGraph, manifestDependencies, resourceId));
}
else {
unscannedFiles.push(filePath);
}
});
return unscannedFiles;
}
function ensureDependencies(id, metadata) {
metadata.importPaths.forEach(importId => {
const fileGraph = ensureFileGraph(importId, false, undefined);
if (fileGraph.importers.includes(id) == false) {
fileGraph.importers.push(id);
}
});
metadata.exportPaths.forEach(exportId => {
const fileGraph = ensureFileGraph(exportId, false, undefined);
if (fileGraph.exporters.includes(id) == false) {
fileGraph.exporters.push(id);
}
});
}
function ensureFileGraph(id, entry, resourceId) {
if (!fileGraphs[id]) {
if (utils_1.pathUtils.isSourceCodePath(id)) {
if (utils_1.pathUtils.isJavaScriptSuperset(id)) {
fileGraphs[id] = initFileGraphJavaScript(id, {}, entry, false);
}
else {
fileGraphs[id] = initFileGraph(id, entry, false);
}
}
else {
if (id.endsWith('.css') || id.endsWith('.svg')) {
fileGraphs[id] = initFileGraph(id, entry, true);
}
else {
fileGraphs[id] = initFileGraphJavaScript(id, {}, entry, true);
}
}
}
if (entry && !!resourceId) {
fileGraphs[id].entry = true;
fileGraphs[id].resourceId = resourceId;
}
else if (resourceId && fileGraphs[id].connectedResourceIds.includes(resourceId) == false) {
fileGraphs[id].connectedResourceIds.push(resourceId);
}
return fileGraphs[id];
}
function initFileGraph(id, entry, bareImport) {
return {
id: id,
entry: entry,
preBundled: false,
extension: path_1.default.extname(id),
resourceId: undefined,
connectedResourceIds: [],
importers: [],
exporters: [],
js: undefined,
bareImport: bareImport
};
}
function initFileGraphJavaScript(id, graph, entry, bareImport) {
return {
id: id,
entry: entry,
preBundled: false,
extension: path_1.default.extname(id),
resourceId: undefined,
connectedResourceIds: [],
importers: [],
exporters: [],
js: {
scanned: graph.scanned ? graph.scanned : false,
empty: graph.empty ? graph.empty : false,
metadata: graph.metadata ? graph.metadata : undefined
},
bareImport: bareImport
};
}