UNPKG

@ima/cli

Version:

IMA.js CLI tool to build, develop and work with IMA.js applications.

93 lines (92 loc) 3.96 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.GenerateRunnerPlugin = void 0; const fs_1 = __importDefault(require("fs")); const path_1 = __importDefault(require("path")); const ejs_1 = __importDefault(require("ejs")); const schema_utils_1 = require("schema-utils"); const webpack_1 = require("webpack"); const options_json_1 = __importDefault(require("./options.json")); // Stores runtime code across multiple webpack compilers. const runtimeStorage = {}; /** * This plugin takes care of generating application runtime script * consisting of @ima/core runner polyfill implementation embedded * with the webpack runtime execution code. */ class GenerateRunnerPlugin { #pluginName; #options; #runnerTemplate; constructor(options) { this.#pluginName = this.constructor.name; this.#options = options; // Validate options (0, schema_utils_1.validate)(options_json_1.default, this.#options, { name: this.#pluginName, baseDataPath: 'options', }); // Pre-compile runner ejs template this.#runnerTemplate = ejs_1.default.compile(options.runnerTemplate ?? fs_1.default.readFileSync(path_1.default.resolve(path_1.default.dirname(require.resolve('@ima/core')), '../../polyfill/runner.ejs'), 'utf8')); } apply(compiler) { compiler.hooks.compilation.tap(this.#pluginName, compilation => { compilation.hooks.processAssets.tapPromise({ name: this.#pluginName, stage: compiler.webpack.Compilation.PROCESS_ASSETS_STAGE_DERIVED, }, (assets) => this.generate(assets, compilation)); }); } /** * Generate runner code from compiled assets. */ async generate(assets, compilation) { const runtimeAsset = Object.keys(assets).find(assetName => /runtime\.(.+)\.js$/.test(assetName)); if (!runtimeAsset) { return; } const { name, forceLegacy, command, legacy } = this.#options.context; const { disableLegacyBuild } = this.#options.imaConfig; // Save runtime code into storage runtimeStorage[name === 'client.es' ? 'esRuntimeCode' : 'runtimeCode'] = assets[runtimeAsset].source().toString(); const { esRuntimeCode, runtimeCode } = runtimeStorage; // Delete runtime asset since we inline it in the IMA runner. compilation.deleteAsset(runtimeAsset); if ((disableLegacyBuild && esRuntimeCode) || (command == 'build' && esRuntimeCode && runtimeCode) || (command == 'dev' && legacy && esRuntimeCode && runtimeCode) || (command == 'dev' && !legacy && esRuntimeCode)) { const generatedRunner = this.#runnerTemplate({ forceLegacy: !!forceLegacy, esRuntime: esRuntimeCode ? this.#addSlashes(esRuntimeCode) : '// es.runtime not generated', runtime: runtimeCode ? this.#addSlashes(runtimeCode) : '// runtime not generated', }); // Emit compiled ima runner with embedded runtime codes return compilation.emitAsset('./server/runner.js', new webpack_1.sources.RawSource(generatedRunner)); } } /** * Add slashes to the runtime code so it can be used * as a string argument in the Function constructor. */ #addSlashes(code) { return code .replace(/\\/g, '\\\\') .replace(/\t/g, '\\t') .replace(/\n/g, '\\n') .replace(/\f/g, '\\f') .replace(/\r/g, '\\r') .replace(/'/g, "\\'") .replace(/"/g, '\\"'); } } exports.GenerateRunnerPlugin = GenerateRunnerPlugin;