UNPKG

@nx/rspack

Version:

The Nx Plugin for Rspack contains executors and generators that support building applications using Rspack.

208 lines (207 loc) • 11.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.servePostTargetTransformerFactory = servePostTargetTransformerFactory; const tslib_1 = require("tslib"); const devkit_1 = require("@nx/devkit"); const plugin_migration_utils_1 = require("@nx/devkit/src/generators/plugin-migrations/plugin-migration-utils"); const tsquery_1 = require("@phenomnomnominal/tsquery"); const path_1 = require("path"); const ts = tslib_1.__importStar(require("typescript")); const serve_path_1 = require("../../../executors/dev-server/lib/serve-path"); const ast_1 = require("./ast"); function servePostTargetTransformerFactory(migrationContext) { return async function servePostTargetTransformer(target, tree, projectDetails, inferredTarget) { const context = { ...migrationContext, projectName: projectDetails.projectName, projectRoot: projectDetails.root, }; const { devServerOptions, rspackConfigPath } = await processOptions(tree, target, context); updateRspackConfig(tree, rspackConfigPath, devServerOptions, context); if (target.outputs) { (0, plugin_migration_utils_1.processTargetOutputs)(target, [], inferredTarget, { projectName: projectDetails.projectName, projectRoot: projectDetails.root, }); } return target; }; } async function processOptions(tree, target, context) { const executorContext = { cwd: process.cwd(), nxJsonConfiguration: (0, devkit_1.readJson)(tree, 'nx.json'), projectGraph: context.projectGraph, projectName: context.projectName, projectsConfigurations: Object.entries(context.projectGraph.nodes).reduce((acc, [projectName, project]) => { acc.projects[projectName] = project.data; return acc; }, { version: 1, projects: {} }), root: context.workspaceRoot, }; const buildTarget = (0, devkit_1.parseTargetString)(target.options.buildTarget, executorContext); const buildOptions = (0, devkit_1.readTargetOptions)(buildTarget, executorContext); // it must exist, we validated it in the project filter const rspackConfigPath = buildOptions.rspackConfig; const defaultOptions = extractDevServerOptions(target.options, context); applyDefaults(defaultOptions, buildOptions); const devServerOptions = { default: defaultOptions, }; if (target.configurations && Object.keys(target.configurations).length) { for (const [configName, config] of Object.entries(target.configurations)) { devServerOptions[configName] = extractDevServerOptions(config, context); } } return { devServerOptions, rspackConfigPath: rspackConfigPath }; } function extractDevServerOptions(options, context) { const devServerOptions = {}; for (const [key, value] of Object.entries(options)) { if (key === 'ssl' || key === 'sslCert' || key === 'sslKey') { if (key === 'ssl' || 'ssl' in options) { if (options.ssl) { devServerOptions.server = { type: 'https' }; if (options.sslCert && options.sslKey) { devServerOptions.server.options = {}; devServerOptions.server.options.cert = (0, plugin_migration_utils_1.toProjectRelativePath)(options.sslCert, context.projectRoot); devServerOptions.server.options.key = (0, plugin_migration_utils_1.toProjectRelativePath)(options.sslKey, context.projectRoot); } else if (options.sslCert) { context.logger.addLog({ executorName: '@nx/rspack:dev-server', log: 'The "sslCert" option was set but "sslKey" was missing and "ssl" was set to "true". This means that "sslCert" was ignored by the executor. It has been removed from the options.', project: context.projectName, }); } else if (options.sslKey) { context.logger.addLog({ executorName: '@nx/rspack:dev-server', log: 'The "sslKey" option was set but "sslCert" was missing and "ssl" was set to "true". This means that "sslKey" was ignored by the executor. It has been removed from the options.', project: context.projectName, }); } } else if (options.sslCert || options.sslKey) { context.logger.addLog({ executorName: '@nx/rspack:dev-server', log: 'The "sslCert" and/or "sslKey" were set with "ssl" set to "false". This means they were ignored by the executor. They have been removed from the options.', project: context.projectName, }); } delete options.ssl; delete options.sslCert; delete options.sslKey; } else if (options.sslCert || options.sslKey) { context.logger.addLog({ executorName: '@nx/rspack:dev-server', log: 'The "sslCert" and/or "sslKey" were set but the "ssl" was not set. This means they were ignored by the executor. They have been removed from the options.', project: context.projectName, }); delete options.sslCert; delete options.sslKey; } } else if (key === 'buildTarget') { delete options.buildTarget; } else { devServerOptions[key] = value; delete options[key]; } } return devServerOptions; } function applyDefaults(options, buildOptions) { if (options.port === undefined) { options.port = 4200; } options.headers = { 'Access-Control-Allow-Origin': '*' }; const servePath = (0, serve_path_1.buildServePath)(buildOptions); options.historyApiFallback = { index: buildOptions.index && `${servePath}${(0, path_1.basename)(buildOptions.index)}`, disableDotRule: true, htmlAcceptHeaders: ['text/html', 'application/xhtml+xml'], }; } function getProxyConfig(root, proxyConfig) { const proxyPath = (0, path_1.resolve)(root, proxyConfig); return require(proxyPath); } function updateRspackConfig(tree, rspackConfigPath, devServerOptions, context) { let sourceFile; let rspackConfigText; const updateSources = () => { rspackConfigText = tree.read(rspackConfigPath, 'utf-8'); sourceFile = (0, tsquery_1.ast)(rspackConfigText); }; updateSources(); setOptionsInRspackConfig(tree, rspackConfigText, sourceFile, rspackConfigPath, devServerOptions); updateSources(); setDevServerOptionsInRspackConfig(tree, rspackConfigText, sourceFile, rspackConfigPath, context); } function setOptionsInRspackConfig(tree, text, sourceFile, rspackConfigPath, devServerOptions) { const { default: defaultOptions, ...configurationOptions } = devServerOptions; const configValuesSelector = 'VariableDeclaration:has(Identifier[name=configValues]) ObjectLiteralExpression'; const configValuesObject = (0, tsquery_1.query)(sourceFile, configValuesSelector)[0]; // configValues must exist at this point, we added it when processing the build target /** * const configValues = { * ... * serve: { * default: { ... }, * configuration1: { ... }, * ... * }, */ const updatedConfigValuesObject = ts.factory.updateObjectLiteralExpression(configValuesObject, [ ...configValuesObject.properties, ts.factory.createPropertyAssignment('serve', ts.factory.createObjectLiteralExpression([ ts.factory.createPropertyAssignment('default', ts.factory.createObjectLiteralExpression(Object.entries(defaultOptions).map(([key, value]) => (0, ast_1.toPropertyAssignment)(key, value)))), ...(configurationOptions ? Object.entries(configurationOptions).map(([key, value]) => ts.factory.createPropertyAssignment(key, ts.factory.createObjectLiteralExpression(Object.entries(value).map(([key, value]) => (0, ast_1.toPropertyAssignment)(key, value))))) : []), ])), ]); text = `${text.slice(0, configValuesObject.getStart())}${ts .createPrinter() .printNode(ts.EmitHint.Unspecified, updatedConfigValuesObject, sourceFile)}${text.slice(configValuesObject.getEnd())}`; tree.write(rspackConfigPath, text); sourceFile = (0, tsquery_1.ast)(text); const buildOptionsSelector = 'VariableStatement:has(VariableDeclaration:has(Identifier[name=buildOptions]))'; const buildOptionsStatement = (0, tsquery_1.query)(sourceFile, buildOptionsSelector)[0]; text = `${text.slice(0, buildOptionsStatement.getEnd())} const devServerOptions = { ...configValues.serve.default, ...configValues.serve[configuration], };${text.slice(buildOptionsStatement.getEnd())}`; tree.write(rspackConfigPath, text); } function setDevServerOptionsInRspackConfig(tree, text, sourceFile, rspackConfigPath, context) { const rspackConfigDevServerSelector = 'ObjectLiteralExpression > PropertyAssignment:has(Identifier[name=devServer])'; const rspackConfigDevServer = (0, tsquery_1.query)(sourceFile, rspackConfigDevServerSelector)[0]; if (rspackConfigDevServer) { context.logger.addLog({ executorName: '@nx/rspack:dev-server', log: `The "devServer" option is already set in the rspack config. The migration doesn't support updating it. Please review it and make any necessary changes manually.`, project: context.projectName, }); text = `${text.slice(0, rspackConfigDevServer.getStart())}// This is the untouched "devServer" option from the original rspack config. Please review it and make any necessary changes manually. ${text.slice(rspackConfigDevServer.getStart())}`; tree.write(rspackConfigPath, text); // If the devServer property already exists, we don't know how to merge the // options, so we leave it as is. return; } const rspackConfigSelector = 'ObjectLiteralExpression:has(PropertyAssignment:has(Identifier[name=plugins]))'; const rspackConfig = (0, tsquery_1.query)(sourceFile, rspackConfigSelector)[0]; const updatedRspackConfig = ts.factory.updateObjectLiteralExpression(rspackConfig, [ ts.factory.createPropertyAssignment('devServer', ts.factory.createIdentifier('devServerOptions')), ...rspackConfig.properties, ]); text = `${text.slice(0, rspackConfig.getStart())}${ts .createPrinter() .printNode(ts.EmitHint.Unspecified, updatedRspackConfig, sourceFile)}${text.slice(rspackConfig.getEnd())}`; tree.write(rspackConfigPath, text); }