UNPKG

@nx/vite

Version:

The Nx Plugin for building and testing applications using Vite

481 lines (480 loc) • 20 kB
"use strict"; function _export(target, all) { for(var name in all)Object.defineProperty(target, name, { enumerable: true, get: all[name] }); } _export(exports, { createDependencies: function() { return createDependencies; }, createNodes: function() { return createNodes; }, createNodesV2: function() { return createNodesV2; } }); const _extends = require("@swc/helpers/_/_extends"); const _devkit = require("@nx/devkit"); const _path = require("path"); const _getnamedinputs = require("@nx/devkit/src/utils/get-named-inputs"); const _fs = require("fs"); const _calculatehashforcreatenodes = require("@nx/devkit/src/utils/calculate-hash-for-create-nodes"); const _cachedirectory = require("nx/src/utils/cache-directory"); const _js = require("@nx/js"); const _executorutils = require("../utils/executor-utils"); const _filehasher = require("nx/src/hasher/file-hasher"); const _minimatch = require("minimatch"); const _tssolutionsetup = require("@nx/js/src/utils/typescript/ts-solution-setup"); const _util = require("@nx/js/src/plugins/typescript/util"); const pmc = (0, _devkit.getPackageManagerCommand)(); function readTargetsCache(cachePath) { return process.env.NX_CACHE_PROJECT_GRAPH !== 'false' && (0, _fs.existsSync)(cachePath) ? (0, _devkit.readJsonFile)(cachePath) : {}; } function writeTargetsToCache(cachePath, results) { (0, _devkit.writeJsonFile)(cachePath, results); } const createDependencies = ()=>{ return []; }; const viteVitestConfigGlob = '**/{vite,vitest}.config.{js,ts,mjs,mts,cjs,cts}'; const createNodesV2 = [ viteVitestConfigGlob, async (configFilePaths, options, context)=>{ const optionsHash = (0, _filehasher.hashObject)(options); const normalizedOptions = normalizeOptions(options); const cachePath = (0, _path.join)(_cachedirectory.workspaceDataDirectory, `vite-${optionsHash}.hash`); const targetsCache = readTargetsCache(cachePath); const isUsingTsSolutionSetup = (0, _tssolutionsetup.isUsingTsSolutionSetup)(); const { roots: projectRoots, configFiles: validConfigFiles } = configFilePaths.reduce((acc, configFile)=>{ const potentialRoot = (0, _path.dirname)(configFile); if (checkIfConfigFileShouldBeProject(potentialRoot, context)) { acc.roots.push(potentialRoot); acc.configFiles.push(configFile); } return acc; }, { roots: [], configFiles: [] }); const lockfile = (0, _js.getLockFileName)((0, _devkit.detectPackageManager)(context.workspaceRoot)); const hashes = await (0, _calculatehashforcreatenodes.calculateHashesForCreateNodes)(projectRoots, _extends._({}, normalizedOptions, { isUsingTsSolutionSetup }), context, projectRoots.map((r)=>[ lockfile ])); try { return await (0, _devkit.createNodesFromFiles)(async (configFile, _, context, idx)=>{ var _targetsCache, _hash; const projectRoot = (0, _path.dirname)(configFile); // Do not create a project if package.json and project.json isn't there. const siblingFiles = (0, _fs.readdirSync)((0, _path.join)(context.workspaceRoot, projectRoot)); var _siblingFiles_filter; const tsConfigFiles = (_siblingFiles_filter = siblingFiles.filter((p)=>(0, _minimatch.minimatch)(p, 'tsconfig*{.json,.*.json}'))) != null ? _siblingFiles_filter : []; const hasReactRouterConfig = siblingFiles.some((configFile)=>{ const parts = configFile.split('.'); return parts[0] === 'react-router' && parts[1] === 'config' && parts.length > 2; }); // results from vitest.config.js will be different from results of vite.config.js // but the hash will be the same because it is based on the files under the project root. // Adding the config file path to the hash ensures that the final hash value is different // for different config files. const hash = hashes[idx] + configFile; var _1; const { projectType, metadata, targets } = (_1 = (_targetsCache = targetsCache)[_hash = hash]) != null ? _1 : _targetsCache[_hash] = await buildViteTargets(configFile, projectRoot, normalizedOptions, tsConfigFiles, hasReactRouterConfig, isUsingTsSolutionSetup, context); const project = { root: projectRoot, targets, metadata }; // If project is buildable, then the project type. // If it is not buildable, then leave it to other plugins/project.json to set the project type. if (project.targets[normalizedOptions.buildTargetName]) { project.projectType = projectType; } return { projects: { [projectRoot]: project } }; }, validConfigFiles, options, context); } finally{ writeTargetsToCache(cachePath, targetsCache); } } ]; const createNodes = [ viteVitestConfigGlob, async (configFilePath, options, context)=>{ _devkit.logger.warn('`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.'); const projectRoot = (0, _path.dirname)(configFilePath); // Do not create a project if package.json and project.json isn't there. const siblingFiles = (0, _fs.readdirSync)((0, _path.join)(context.workspaceRoot, projectRoot)); if (!siblingFiles.includes('package.json') && !siblingFiles.includes('project.json')) { return {}; } var _siblingFiles_filter; const tsConfigFiles = (_siblingFiles_filter = siblingFiles.filter((p)=>(0, _minimatch.minimatch)(p, 'tsconfig*{.json,.*.json}'))) != null ? _siblingFiles_filter : []; const hasReactRouterConfig = siblingFiles.some((configFile)=>{ const parts = configFile.split('.'); return parts[0] === 'react-router' && parts[1] === 'config' && parts.length > 2; }); const normalizedOptions = normalizeOptions(options); const isUsingTsSolutionSetup = (0, _tssolutionsetup.isUsingTsSolutionSetup)(); const { projectType, metadata, targets } = await buildViteTargets(configFilePath, projectRoot, normalizedOptions, tsConfigFiles, hasReactRouterConfig, isUsingTsSolutionSetup, context); const project = { root: projectRoot, targets, metadata }; // If project is buildable, then the project type. // If it is not buildable, then leave it to other plugins/project.json to set the project type. if (project.targets[normalizedOptions.buildTargetName]) { project.projectType = projectType; } return { projects: { [projectRoot]: project } }; } ]; async function buildViteTargets(configFilePath, projectRoot, options, tsConfigFiles, hasReactRouterConfig, isUsingTsSolutionSetup, context) { var _viteBuildConfig_build; const absoluteConfigFilePath = (0, _devkit.joinPathFragments)(context.workspaceRoot, configFilePath); // Workaround for the `build$3 is not a function` error that we sometimes see in agents. // This should be removed later once we address the issue properly try { const importEsbuild = ()=>new Function('return import("esbuild")')(); await importEsbuild(); } catch (e) { // do nothing } const { resolveConfig } = await (0, _executorutils.loadViteDynamicImport)(); const viteBuildConfig = await resolveConfig({ configFile: absoluteConfigFilePath, mode: 'development' }, 'build'); const { buildOutputs, testOutputs, hasTest, isBuildable, hasServeConfig } = getOutputs(viteBuildConfig, projectRoot, context.workspaceRoot); const namedInputs = (0, _getnamedinputs.getNamedInputs)(projectRoot, context); const targets = {}; // if file is vitest.config or vite.config has definition for test, create target for test if (configFilePath.includes('vitest.config') || hasTest) { targets[options.testTargetName] = await testTarget(namedInputs, testOutputs, projectRoot); } if (hasReactRouterConfig) { // If we have a react-router config, we can skip the rest of the targets return { targets, metadata: {}, projectType: 'application' }; } // If file is not vitest.config and buildable, create targets for build, serve, preview and serve-static const hasRemixPlugin = viteBuildConfig.plugins && viteBuildConfig.plugins.some((p)=>p.name === 'remix'); if (!configFilePath.includes('vitest.config') && !hasRemixPlugin && isBuildable) { var _viteBuildConfig_build1; targets[options.buildTargetName] = await buildTarget(options.buildTargetName, namedInputs, buildOutputs, projectRoot, isUsingTsSolutionSetup); // If running in library mode, then there is nothing to serve. if (!((_viteBuildConfig_build1 = viteBuildConfig.build) == null ? void 0 : _viteBuildConfig_build1.lib) || hasServeConfig) { const devTarget = serveTarget(projectRoot, isUsingTsSolutionSetup); targets[options.serveTargetName] = _extends._({}, devTarget, { metadata: _extends._({}, devTarget.metadata, { deprecated: 'Use devTargetName instead. This option will be removed in Nx 22.' }) }); targets[options.devTargetName] = devTarget; targets[options.previewTargetName] = previewTarget(projectRoot, options.buildTargetName); targets[options.serveStaticTargetName] = serveStaticTarget(options, isUsingTsSolutionSetup); } } if (tsConfigFiles.length) { var _find; const tsConfigToUse = (_find = [ 'tsconfig.app.json', 'tsconfig.lib.json', 'tsconfig.json' ].find((t)=>tsConfigFiles.includes(t))) != null ? _find : tsConfigFiles[0]; targets[options.typecheckTargetName] = { cache: true, inputs: [ ...'production' in namedInputs ? [ 'production', '^production' ] : [ 'default', '^default' ], { externalDependencies: [ 'typescript' ] } ], command: isUsingTsSolutionSetup ? `tsc --build --emitDeclarationOnly` : `tsc --noEmit -p ${tsConfigToUse}`, options: { cwd: (0, _devkit.joinPathFragments)(projectRoot) }, metadata: { description: `Runs type-checking for the project.`, technologies: [ 'typescript' ], help: { command: isUsingTsSolutionSetup ? `${pmc.exec} tsc --build --help` : `${pmc.exec} tsc -p ${tsConfigToUse} --help`, example: isUsingTsSolutionSetup ? { args: [ '--force' ] } : { options: { noEmit: true } } } } }; if (isUsingTsSolutionSetup) { targets[options.typecheckTargetName].dependsOn = [ `^${options.typecheckTargetName}` ]; targets[options.typecheckTargetName].syncGenerators = [ '@nx/js:typescript-sync' ]; } } (0, _util.addBuildAndWatchDepsTargets)(context.workspaceRoot, projectRoot, targets, options, pmc); const metadata = {}; return { targets, metadata, projectType: ((_viteBuildConfig_build = viteBuildConfig.build) == null ? void 0 : _viteBuildConfig_build.lib) ? 'library' : 'application' }; } async function buildTarget(buildTargetName, namedInputs, outputs, projectRoot, isUsingTsSolutionSetup) { const buildTarget = { command: `vite build`, options: { cwd: (0, _devkit.joinPathFragments)(projectRoot) }, cache: true, dependsOn: [ `^${buildTargetName}` ], inputs: [ ...'production' in namedInputs ? [ 'production', '^production' ] : [ 'default', '^default' ], { externalDependencies: [ 'vite' ] } ], outputs, metadata: { technologies: [ 'vite' ], description: `Run Vite build`, help: { command: `${pmc.exec} vite build --help`, example: { options: { sourcemap: true, manifest: 'manifest.json' } } } } }; if (isUsingTsSolutionSetup) { buildTarget.syncGenerators = [ '@nx/js:typescript-sync' ]; } return buildTarget; } function serveTarget(projectRoot, isUsingTsSolutionSetup) { const targetConfig = { command: `vite`, options: { cwd: (0, _devkit.joinPathFragments)(projectRoot) }, metadata: { technologies: [ 'vite' ], description: `Starts Vite dev server`, help: { command: `${pmc.exec} vite --help`, example: { options: { port: 3000 } } } } }; if (isUsingTsSolutionSetup) { targetConfig.syncGenerators = [ '@nx/js:typescript-sync' ]; } return targetConfig; } function previewTarget(projectRoot, buildTargetName) { const targetConfig = { command: `vite preview`, dependsOn: [ buildTargetName ], options: { cwd: (0, _devkit.joinPathFragments)(projectRoot) }, metadata: { technologies: [ 'vite' ], description: `Locally preview Vite production build`, help: { command: `${pmc.exec} vite preview --help`, example: { options: { port: 3000 } } } } }; return targetConfig; } async function testTarget(namedInputs, outputs, projectRoot) { return { command: `vitest`, options: { cwd: (0, _devkit.joinPathFragments)(projectRoot) }, cache: true, inputs: [ ...'production' in namedInputs ? [ 'default', '^production' ] : [ 'default', '^default' ], { externalDependencies: [ 'vitest' ] }, { env: 'CI' } ], outputs, metadata: { technologies: [ 'vite' ], description: `Run Vite tests`, help: { command: `${pmc.exec} vitest --help`, example: { options: { bail: 1, coverage: true } } } } }; } function serveStaticTarget(options, isUsingTsSolutionSetup) { const targetConfig = { executor: '@nx/web:file-server', options: { buildTarget: `${options.buildTargetName}`, spa: true } }; if (isUsingTsSolutionSetup) { targetConfig.syncGenerators = [ '@nx/js:typescript-sync' ]; } return targetConfig; } function getOutputs(viteBuildConfig, projectRoot, workspaceRoot) { var _build_rollupOptions, _test_coverage; const { build, test, server } = viteBuildConfig; const buildOutputPath = normalizeOutputPath(build == null ? void 0 : build.outDir, projectRoot, workspaceRoot, 'dist'); const isBuildable = (build == null ? void 0 : build.lib) || (build == null ? void 0 : (_build_rollupOptions = build.rollupOptions) == null ? void 0 : _build_rollupOptions.input) || (0, _fs.existsSync)((0, _path.join)(workspaceRoot, projectRoot, 'index.html')); const hasServeConfig = Boolean(server); const reportsDirectoryPath = normalizeOutputPath(test == null ? void 0 : (_test_coverage = test.coverage) == null ? void 0 : _test_coverage.reportsDirectory, projectRoot, workspaceRoot, 'coverage'); return { buildOutputs: [ buildOutputPath ], testOutputs: [ reportsDirectoryPath ], hasTest: !!test, isBuildable, hasServeConfig }; } function normalizeOutputPath(outputPath, projectRoot, workspaceRoot, path) { if (!outputPath) { if (projectRoot === '.') { return `{projectRoot}/${path}`; } else { return `{workspaceRoot}/${path}/{projectRoot}`; } } else { if ((0, _path.isAbsolute)(outputPath)) { return `{workspaceRoot}/${(0, _path.relative)(workspaceRoot, outputPath)}`; } else { if (outputPath.startsWith('..')) { return (0, _path.join)('{workspaceRoot}', (0, _path.join)(projectRoot, outputPath)); } else { return (0, _path.join)('{projectRoot}', outputPath); } } } } function normalizeOptions(options) { var _options, _options1, _options2, _options3, _options4, _options5, _options6; options != null ? options : options = {}; var _buildTargetName; (_buildTargetName = (_options = options).buildTargetName) != null ? _buildTargetName : _options.buildTargetName = 'build'; var _serveTargetName; (_serveTargetName = (_options1 = options).serveTargetName) != null ? _serveTargetName : _options1.serveTargetName = 'serve'; var _devTargetName; (_devTargetName = (_options2 = options).devTargetName) != null ? _devTargetName : _options2.devTargetName = 'dev'; var _previewTargetName; (_previewTargetName = (_options3 = options).previewTargetName) != null ? _previewTargetName : _options3.previewTargetName = 'preview'; var _testTargetName; (_testTargetName = (_options4 = options).testTargetName) != null ? _testTargetName : _options4.testTargetName = 'test'; var _serveStaticTargetName; (_serveStaticTargetName = (_options5 = options).serveStaticTargetName) != null ? _serveStaticTargetName : _options5.serveStaticTargetName = 'serve-static'; var _typecheckTargetName; (_typecheckTargetName = (_options6 = options).typecheckTargetName) != null ? _typecheckTargetName : _options6.typecheckTargetName = 'typecheck'; return options; } function checkIfConfigFileShouldBeProject(projectRoot, context) { // Do not create a project if package.json and project.json isn't there. const siblingFiles = (0, _fs.readdirSync)((0, _path.join)(context.workspaceRoot, projectRoot)); if (!siblingFiles.includes('package.json') && !siblingFiles.includes('project.json')) { return false; } return true; } //# sourceMappingURL=plugin.js.map