UNPKG

@tscc/rollup-plugin-tscc

Version:

A rollup plugin to use tscc module specification

142 lines (141 loc) 7.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const goog_shim_mixin_1 = require("./goog_shim_mixin"); const merge_chunks_1 = require("./merge_chunks"); const sort_chunks_1 = require("./sort_chunks"); const TsccSpecRollupFacade_1 = require("./spec/TsccSpecRollupFacade"); const path = require("path"); const pluginImpl = (pluginOptions) => { const spec = TsccSpecRollupFacade_1.default.loadSpec(pluginOptions); const isManyModuleBuild = spec.getOrderedModuleSpecs().length > 1; const globals = spec.getRollupExternalModuleNamesToGlobalMap(); /* Plugin methods start */ const name = "rollup-plugin-tscc"; const options = (options = {}) => { // Add entry files read fom tsccconfig options.input = spec.getRollupOutputNameToEntryFileMap(); options.external = spec.getExternalModuleNames(); return options; }; const outputOptions = (outputOptions = {}) => { outputOptions.dir = '.'; outputOptions.entryFileNames = "[name].js"; outputOptions.chunkFileNames = "_"; // rollup makes these unique anyway. outputOptions.globals = globals; if (isManyModuleBuild) { // For many-module build, currently only iife builds are available. // Intermediate build format is 'es'. outputOptions.format = 'es'; } else { outputOptions.format = spec.getRollupOutputModuleFormat(); } return outputOptions; }; const resolveId = (id, importer) => { /** * Getting absolute paths for external modules working has been pretty tricky. I haven't * tracked down the exact cause, but sometimes external modules' paths are relative to CWD, * sometimes relative to the common demoninator of files (check inputBase of rollup source). * It seems that this is consistent internally, but not when user-provided absolute paths * are involved. In particular the "external-modules-in-many-module-build" test case fails. * * Prior to rollup 2.44.0, we have used "paths" output option to force rollup to keep use * absolute paths for external modules internally. "paths" option is mainly intended to * replace external module paths to 3rd-party CDN urls in the bundle output, so our use is * more like an 'exploit'. One place where one replaces an absolute path to a relative path * is `ExternalModule.setRenderPath` which sets `renderPath` which is later resolved * relatively from certain path to compute final path in import statements. If * outputOption.path function is provided, the value produced by this function is used as * `renderPath` instead, so we are hooking into it so that `renderPath` is set to an * absolute path. * * Since 2.44.0, it has supported returning {external: 'absolute'} value from `resolveId` * hook, which seems to be achieving what we have done using `output.paths` option. In * particular it disables rollup's 'helpful' renormalization of paths, see * https://github.com/rollup/rollup/blob/a8647dac0fe46c86183be8596ef7de25bc5b4e4b/src/ExternalModule.ts#L94, * https://github.com/rollup/rollup/blob/983c0cac83727a13af834fe79dfeef89da4fb84b/src/Chunk.ts#L699. * The related PR is https://github.com/rollup/rollup/pull/4021. * * These paths are then used in intermediate chunks, and will not be emitted in final bundle * due to the helpful renormalization which we do not disable in the secondary bundling. */ if (importer) { const resolved = path.resolve(path.dirname(importer), id); if (resolved in globals) { return { id: resolved, external: "absolute" }; } } let depsPath = spec.resolveRollupExternalDeps(id); if (depsPath) { return path.resolve(process.cwd(), depsPath); // Using 'posix' does not work well with rollup internals } }; // Returning null defers to other load functions, see https://rollupjs.org/guide/en/#load const load = (id) => null; const generateBundle = handleError(async function (options, bundle, isWrite) { // Quick path for single-module builds if (spec.getOrderedModuleSpecs().length === 1) return; // Get entry dependency from spec const entryDeps = spec.getRollupOutputNameDependencyMap(); // Get chunk dependency from rollup.OutputBundle const chunkDeps = {}; for (let [fileName, chunkInfo] of Object.entries(bundle)) { // TODO This is a possible source of conflicts with other rollup plugins. Some plugins // may add unexpected chunks. In general, it is not clear what TSCC should do in such // cases. A safe way would be to strip out such chunks and deal only with chunks that // are expected to be emitted. We may trim such chunks here. if (!isChunk(chunkInfo)) continue; chunkDeps[fileName] = []; for (let imported of chunkInfo.imports) { chunkDeps[fileName].push(imported); } } // Compute chunk allocation const chunkAllocation = (0, sort_chunks_1.default)(chunkDeps, entryDeps); const chunkMerger = new merge_chunks_1.ChunkMerger(chunkAllocation, bundle, globals); /** * Hack `bundle` object, as described in {@link https://github.com/rollup/rollup/issues/2938} */ // 0. Merge intermediate chunks to appropriate entry chunk const mergedChunks = spec.getRollupOutputModuleFormat() === 'iife' ? await Promise.all([...entryDeps.keys()] .map((entry) => chunkMerger.performSingleEntryBuild(entry, 'iife'))) : await chunkMerger.performCodeSplittingBuild('es'); // 1. Delete keys for intermediate chunks for (let entry of chunkAllocation.keys()) { for (let chunk of chunkAllocation.iterateValues(entry)) { delete bundle[chunk]; } } // 2. Add the merged chunks to the bundle object for (let chunk of mergedChunks) { bundle[chunk.fileName] = chunk; } return; }); return (0, goog_shim_mixin_1.googShimMixin)({ name, generateBundle, options, outputOptions, resolveId, load }); }; function isChunk(output) { return output.type === 'chunk'; } function handleError(hook) { return async function () { try { return await Reflect.apply(hook, this, arguments); } catch (e) { // Handle known type of errors if (e instanceof sort_chunks_1.ChunkSortError || e instanceof merge_chunks_1.ChunkMergeError) { this.error(e.message); } else { throw e; } } }; } exports.default = pluginImpl;