UNPKG

@wrench/roll-typescript

Version:

plugin for bundling TypeScript with support of modular output and declaration bundle

205 lines (183 loc) 7.32 kB
Object.defineProperty(exports, "__esModule", { value: true }); const tslib_1 = require("tslib"); const colors_1 = require("colors"); const path_1 = tslib_1.__importDefault(require("path")); const bundle_dts_1 = require("./bundle-dts"); const dts_1 = require("./dts"); const host_1 = require("./host"); const project_1 = require("./project"); const util_1 = require("./util"); const NAME = "@wrench/typescript"; const VIRTUAL_NAME = `_virtual/${NAME}`; const EXPORT_NULL = "exports = null;"; function typescript(options) { options = Object.assign({}, options); if (options.types) options.types = path_1.default.resolve(options.types); let isExternal; let cache; let exclude; let modular; let project; let dtsPretty; let compilerOptions; let inputs; let pending; let shouldBundleDts; return { name: NAME, buildStart(input) { cache = new Map(); exclude = new Set([NAME, VIRTUAL_NAME]); modular = input.preserveModules; [project, inputs] = util_1.lazy(this, "project", project_1.createProject, options, input); const { rootDir, rootDirs } = project.options; const roots = rootDirs ? rootDirs : rootDir ? [rootDir] : null; isExternal = util_1.createIsExternal(roots, options.external); const dependencies = host_1.collectDependencies(project, inputs, true); const localDependencies = dependencies.filter(x => isExternal(x) === false); pending = new Set(localDependencies); project.setFileNames(localDependencies); project.reportDiagnostic = host_1.createReportDiagnosticByPlugin(this); shouldBundleDts = !!(!modular && project.options.declarationDir && options.types); compilerOptions = project.options; dtsPretty = util_1.lazy(this, "dts-pretty", dtsPrettyFactory); if (modular) for (const id of pending) this.emitFile({ id, type: "chunk" }); }, resolveId(specifier, importer) { if (host_1.isTsOrTsx(project, importer)) { const id = host_1.resolve(project, importer, specifier); const external = isExternal(specifier, importer, id); return { id, external, moduleSideEffects: true }; } }, load(id) { if (id === NAME) return EXPORT_NULL; }, transform(code, fileName) { pending.delete(fileName); if (fileName === NAME) return; if (!host_1.isTsOrTsx(project, fileName)) return; project.updateScript(fileName, code); const program = project.getProgram(); const out = host_1.emitByProgram(program, project, fileName); const { js, jsmap, dts, dtsmap } = out; if (!modular) { if (dts) host_1.writeOutputFile(project, dts); if (dtsmap) host_1.writeOutputFile(project, dtsmap); } if (isEmptyCode(js.text)) js.text = EXPORT_NULL; return { code: js.text, map: jsmap && jsmap.text, moduleSideEffects: true, }; }, renderStart() { if (!modular) { flush(project, pending, true); pending.clear(); } }, renderChunk(code, chunk, output) { return tslib_1.__awaiter(this, void 0, void 0, function* () { if (chunk.fileName === VIRTUAL_NAME) return; if (modular) { const host = util_1.lazy2(cache, output, checkProgramDirty, this, outputHostKey, project_1.forkHostByOutput, output, project, compilerOptions); const program = host.getProgram(); const out = host_1.emitByProgram(program, host, chunk.facadeModuleId); const { js, jsmap, dts, dtsmap } = out; chunk.fileName = js.name; if (output.banner && chunk.isEntry) js.text = [(yield output.banner), js.text].join(host.getNewLine()); if (dts) { dts.text = dtsPretty.format(dts.text, dts.name); host_1.writeOutputFile(project, dts); } if (dtsmap) host_1.writeOutputFile(project, dtsmap); return { code: js.text, map: jsmap && jsmap.text, }; } else { } }); }, generateBundle(output, bundle) { const host = util_1.lazy2(cache, output, checkProgramDirty, this, outputHostKey, project_1.forkHostByOutput, output, project, compilerOptions); for (const key of Object.keys(bundle)) if (isExclude(bundle[key], exclude)) delete bundle[key]; if (shouldBundleDts) { const outDir = path_1.default.resolve(path_1.default.dirname(output.file)); const rel = path_1.default.relative(outDir, options.types); if (rel && !rel.startsWith("..")) { shouldBundleDts = false; const { declarationDir } = project.options; const entry = path_1.default.join(declarationDir, rel); const relTypes = path_1.default.relative(process.cwd(), options.types); console.log(colors_1.cyan(`${entry}${relTypes}`)); host_1.addFileNames(host, host_1.collectDependencies(host, entry)); bundle_dts_1.bundleDts({ entry, program: host.getProgram(), output: options.types, }); } } }, }; } exports.typescript = typescript; function isExclude(chunk, ...excludes) { if (util_1.isOutputChunk(chunk)) for (const exclude of excludes) if (exclude.has(chunk.facadeModuleId)) return true; } function outputHostKey(output) { return `output.host.${output.file || output.dir}`; } function forkESNext(host) { const { ts } = host; return host.fork({ options: { target: ts.ScriptTarget.ESNext, }, }); } function flush(host, fileNames, dtsOnly) { const program = host.getProgram(); for (const fileName of fileNames) host_1.writeEmit(host, host_1.emitByProgram(program, host, fileName, dtsOnly)); } function showBundle(output, bundle) { console.group(colors_1.cyan(output.file || output.dir)); for (const key of Object.keys(bundle)) console.log(bundle[key].fileName); console.groupEnd(); } function isEmptyCode(code) { if (code) { code = code.replace(/\/\/.*/g, ""); code = code.trim(); } return !code; } function checkProgramDirty() { this.checkProgramDirty(); } function dtsPrettyFactory() { return new dts_1.DtsPretty(); }