@nx/vite
Version:
481 lines (480 loc) • 20 kB
JavaScript
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
;