fix(core): re-enable CRA migration to Vite (#30082)
This PR brings back the CRA migration that was missing since Nx 18. ## Current Behavior <!-- This is the behavior we have today --> `nx init` does not migrate CRA apps ## Expected Behavior `nx init` migrates CRA apps to Vite since CRA is deprecated ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
32341d5efc
commit
202b49bdbe
@ -17,10 +17,11 @@ Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`
|
|||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
| Option | Type | Description |
|
| Option | Type | Description |
|
||||||
| ------------------------ | ------- | --------------------------------------------------------------------------------------------------- |
|
| ------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `--help` | boolean | Show help. |
|
| `--force` | boolean | Force the migration to continue and ignore custom webpack setup or uncommitted changes. Only for CRA projects. (Default: `false`) |
|
||||||
| `--interactive` | boolean | When false disables interactive input prompts for options. (Default: `true`) |
|
| `--help` | boolean | Show help. |
|
||||||
| `--nxCloud` | boolean | Set up distributed caching with Nx Cloud. |
|
| `--interactive` | boolean | When false disables interactive input prompts for options. (Default: `true`) |
|
||||||
| `--useDotNxInstallation` | boolean | Initialize an Nx workspace setup in the .nx directory of the current repository. (Default: `false`) |
|
| `--nxCloud` | boolean | Set up distributed caching with Nx Cloud. |
|
||||||
| `--version` | boolean | Show version number. |
|
| `--useDotNxInstallation` | boolean | Initialize an Nx workspace setup in the .nx directory of the current repository. (Default: `false`) |
|
||||||
|
| `--version` | boolean | Show version number. |
|
||||||
|
|||||||
@ -17,10 +17,11 @@ Install `nx` globally to invoke the command directly using `nx`, or use `npx nx`
|
|||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
| Option | Type | Description |
|
| Option | Type | Description |
|
||||||
| ------------------------ | ------- | --------------------------------------------------------------------------------------------------- |
|
| ------------------------ | ------- | --------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `--help` | boolean | Show help. |
|
| `--force` | boolean | Force the migration to continue and ignore custom webpack setup or uncommitted changes. Only for CRA projects. (Default: `false`) |
|
||||||
| `--interactive` | boolean | When false disables interactive input prompts for options. (Default: `true`) |
|
| `--help` | boolean | Show help. |
|
||||||
| `--nxCloud` | boolean | Set up distributed caching with Nx Cloud. |
|
| `--interactive` | boolean | When false disables interactive input prompts for options. (Default: `true`) |
|
||||||
| `--useDotNxInstallation` | boolean | Initialize an Nx workspace setup in the .nx directory of the current repository. (Default: `false`) |
|
| `--nxCloud` | boolean | Set up distributed caching with Nx Cloud. |
|
||||||
| `--version` | boolean | Show version number. |
|
| `--useDotNxInstallation` | boolean | Initialize an Nx workspace setup in the .nx directory of the current repository. (Default: `false`) |
|
||||||
|
| `--version` | boolean | Show version number. |
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
checkFilesDoNotExist,
|
checkFilesDoNotExist,
|
||||||
checkFilesExist,
|
checkFilesExist,
|
||||||
|
createFile,
|
||||||
getPackageManagerCommand,
|
getPackageManagerCommand,
|
||||||
getPublishedVersion,
|
getPublishedVersion,
|
||||||
getSelectedPackageManager,
|
getSelectedPackageManager,
|
||||||
@ -19,118 +20,26 @@ import {
|
|||||||
updateJson,
|
updateJson,
|
||||||
} from '../../utils';
|
} from '../../utils';
|
||||||
|
|
||||||
describe('nx init (for React - legacy)', () => {
|
describe('nx init (React)', () => {
|
||||||
let pmc: ReturnType<typeof getPackageManagerCommand>;
|
let pmc: ReturnType<typeof getPackageManagerCommand>;
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
pmc = getPackageManagerCommand({
|
pmc = getPackageManagerCommand({
|
||||||
packageManager: getSelectedPackageManager(),
|
packageManager: getSelectedPackageManager(),
|
||||||
});
|
});
|
||||||
|
|
||||||
process.env.NX_ADD_PLUGINS = 'false';
|
|
||||||
});
|
});
|
||||||
|
|
||||||
afterAll(() => {
|
it('should convert a CRA project to Vite', () => {
|
||||||
delete process.env.NX_ADD_PLUGINS;
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO(@jaysoo): Please investigate why this test is failing
|
|
||||||
xit('should convert to an integrated workspace with craco (webpack)', () => {
|
|
||||||
const appName = 'my-app';
|
const appName = 'my-app';
|
||||||
createReactApp(appName);
|
createReactApp(appName);
|
||||||
|
|
||||||
const craToNxOutput = runCommand(
|
const craToNxOutput = runCommand(
|
||||||
`${
|
`${
|
||||||
pmc.runUninstalledPackage
|
pmc.runUninstalledPackage
|
||||||
} nx@${getPublishedVersion()} init --no-interactive --integrated --vite=false`
|
} nx@${getPublishedVersion()} init --no-interactive`
|
||||||
);
|
);
|
||||||
|
|
||||||
expect(craToNxOutput).toContain('🎉 Done!');
|
expect(craToNxOutput).toContain('Done!');
|
||||||
|
|
||||||
const packageJson = readJson('package.json');
|
|
||||||
expect(packageJson.devDependencies['@nx/jest']).toBeDefined();
|
|
||||||
expect(packageJson.devDependencies['@nx/vite']).toBeUndefined();
|
|
||||||
expect(packageJson.devDependencies['@nx/webpack']).toBeDefined();
|
|
||||||
expect(packageJson.dependencies['redux']).toBeDefined();
|
|
||||||
expect(packageJson.name).toEqual(appName);
|
|
||||||
|
|
||||||
runCLI(`build ${appName}`, {
|
|
||||||
env: {
|
|
||||||
// since craco 7.1.0 the NODE_ENV is used, since the tests set it
|
|
||||||
// to "test" is causes an issue with React Refresh Babel
|
|
||||||
NODE_ENV: undefined,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
checkFilesExist(`dist/apps/${appName}/index.html`);
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO(crystal, @jaysoo): Investigate why this is failing
|
|
||||||
xit('should convert to an integrated workspace with Vite', () => {
|
|
||||||
// TODO investigate why this is broken
|
|
||||||
const originalPM = process.env.SELECTED_PM;
|
|
||||||
process.env.SELECTED_PM = originalPM === 'pnpm' ? 'yarn' : originalPM;
|
|
||||||
|
|
||||||
const appName = 'my-app';
|
|
||||||
createReactApp(appName);
|
|
||||||
|
|
||||||
const craToNxOutput = runCommand(
|
|
||||||
`${
|
|
||||||
pmc.runUninstalledPackage
|
|
||||||
} nx@${getPublishedVersion()} init --no-interactive --integrated`
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(craToNxOutput).toContain('🎉 Done!');
|
|
||||||
|
|
||||||
const packageJson = readJson('package.json');
|
|
||||||
expect(packageJson.devDependencies['@nx/jest']).toBeUndefined();
|
|
||||||
expect(packageJson.devDependencies['@nx/vite']).toBeDefined();
|
|
||||||
expect(packageJson.devDependencies['@nx/webpack']).toBeUndefined();
|
|
||||||
|
|
||||||
const viteConfig = readFile(`apps/${appName}/vite.config.js`);
|
|
||||||
expect(viteConfig).toContain('port: 4200'); // default port
|
|
||||||
|
|
||||||
runCLI(`build ${appName}`);
|
|
||||||
checkFilesExist(`dist/apps/${appName}/index.html`);
|
|
||||||
|
|
||||||
const unitTestsOutput = runCLI(`test ${appName}`);
|
|
||||||
expect(unitTestsOutput).toContain('Successfully ran target test');
|
|
||||||
process.env.SELECTED_PM = originalPM;
|
|
||||||
});
|
|
||||||
|
|
||||||
// TODO(crystal, @jaysoo): Investigate why this is failing
|
|
||||||
xit('should convert to an integrated workspace with Vite with custom port', () => {
|
|
||||||
// TODO investigate why this is broken
|
|
||||||
const originalPM = process.env.SELECTED_PM;
|
|
||||||
process.env.SELECTED_PM = originalPM === 'pnpm' ? 'yarn' : originalPM;
|
|
||||||
const appName = 'my-app';
|
|
||||||
createReactApp(appName);
|
|
||||||
updateFile(`.env`, `NOT_THE_PORT=8000\nPORT=3000\nSOMETHING_ELSE=whatever`);
|
|
||||||
|
|
||||||
runCommand(
|
|
||||||
`${
|
|
||||||
pmc.runUninstalledPackage
|
|
||||||
} nx@${getPublishedVersion()} init --no-interactive --force --integrated`
|
|
||||||
);
|
|
||||||
|
|
||||||
const viteConfig = readFile(`apps/${appName}/vite.config.js`);
|
|
||||||
expect(viteConfig).toContain('port: 3000');
|
|
||||||
|
|
||||||
const unitTestsOutput = runCLI(`test ${appName}`);
|
|
||||||
expect(unitTestsOutput).toContain('Successfully ran target test');
|
|
||||||
process.env.SELECTED_PM = originalPM;
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should convert to an standalone workspace with Vite', () => {
|
|
||||||
const appName = 'my-app';
|
|
||||||
createReactApp(appName);
|
|
||||||
|
|
||||||
const craToNxOutput = runCommand(
|
|
||||||
`${
|
|
||||||
pmc.runUninstalledPackage
|
|
||||||
} nx@${getPublishedVersion()} init --no-interactive --vite`
|
|
||||||
);
|
|
||||||
|
|
||||||
expect(craToNxOutput).toContain('🎉 Done!');
|
|
||||||
|
|
||||||
checkFilesDoNotExist(
|
checkFilesDoNotExist(
|
||||||
'libs/.gitkeep',
|
'libs/.gitkeep',
|
||||||
@ -144,8 +53,8 @@ describe('nx init (for React - legacy)', () => {
|
|||||||
expect(packageJson.dependencies['redux']).toBeDefined();
|
expect(packageJson.dependencies['redux']).toBeDefined();
|
||||||
expect(packageJson.name).toEqual(appName);
|
expect(packageJson.name).toEqual(appName);
|
||||||
|
|
||||||
const viteConfig = readFile(`vite.config.js`);
|
const viteConfig = readFile(`vite.config.mjs`);
|
||||||
expect(viteConfig).toContain('port: 4200'); // default port
|
expect(viteConfig).toContain('port: 3000'); // default port
|
||||||
|
|
||||||
runCLI(`build ${appName}`);
|
runCLI(`build ${appName}`);
|
||||||
checkFilesExist(`dist/${appName}/index.html`);
|
checkFilesExist(`dist/${appName}/index.html`);
|
||||||
@ -154,6 +63,41 @@ describe('nx init (for React - legacy)', () => {
|
|||||||
expect(unitTestsOutput).toContain('Successfully ran target test');
|
expect(unitTestsOutput).toContain('Successfully ran target test');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should support path aliases', () => {
|
||||||
|
const appName = 'my-app';
|
||||||
|
createReactApp(appName);
|
||||||
|
createFile(
|
||||||
|
'jsconfig.json',
|
||||||
|
JSON.stringify({
|
||||||
|
compilerOptions: {
|
||||||
|
baseUrl: '.',
|
||||||
|
paths: {
|
||||||
|
'foo/*': ['src/foo/*'],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
);
|
||||||
|
createFile('src/foo/Foo.js', `export const Foo = () => <p>Foo</p>;`);
|
||||||
|
updateFile(
|
||||||
|
'src/App.js',
|
||||||
|
`
|
||||||
|
import { Foo } from 'foo/Foo';
|
||||||
|
function App() {
|
||||||
|
return <Foo />;
|
||||||
|
}
|
||||||
|
export default App;
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
runCommand(
|
||||||
|
`${
|
||||||
|
pmc.runUninstalledPackage
|
||||||
|
} nx@${getPublishedVersion()} init --no-interactive`
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => runCLI(`build ${appName}`)).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
function createReactApp(appName: string) {
|
function createReactApp(appName: string) {
|
||||||
createNonNxProjectDirectory();
|
createNonNxProjectDirectory();
|
||||||
const projPath = tmpProjPath();
|
const projPath = tmpProjPath();
|
||||||
|
|||||||
@ -49,6 +49,12 @@ async function withInitOptions(yargs: Argv) {
|
|||||||
description:
|
description:
|
||||||
'Initialize an Nx workspace setup in the .nx directory of the current repository.',
|
'Initialize an Nx workspace setup in the .nx directory of the current repository.',
|
||||||
default: false,
|
default: false,
|
||||||
|
})
|
||||||
|
.option('force', {
|
||||||
|
describe:
|
||||||
|
'Force the migration to continue and ignore custom webpack setup or uncommitted changes. Only for CRA projects.',
|
||||||
|
type: 'boolean',
|
||||||
|
default: false,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
return yargs
|
return yargs
|
||||||
|
|||||||
@ -10,10 +10,12 @@ export function addViteCommandsToPackageScripts(
|
|||||||
const packageJson = readJsonFile(packageJsonPath);
|
const packageJson = readJsonFile(packageJsonPath);
|
||||||
packageJson.scripts = {
|
packageJson.scripts = {
|
||||||
...packageJson.scripts,
|
...packageJson.scripts,
|
||||||
start: 'nx exec -- vite',
|
// These should be replaced by the vite init generator later.
|
||||||
serve: 'nx exec -- vite',
|
start: 'vite',
|
||||||
build: `nx exec -- vite build`,
|
test: 'vitest',
|
||||||
test: 'nx exec -- vitest',
|
dev: 'vite',
|
||||||
|
build: 'vite build',
|
||||||
|
eject: undefined,
|
||||||
};
|
};
|
||||||
writeJsonFile(packageJsonPath, packageJson, { spaces: 2 });
|
writeJsonFile(packageJsonPath, packageJson, { spaces: 2 });
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,29 +1,20 @@
|
|||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import { cpSync, mkdirSync, readdirSync, renameSync, rmSync } from 'node:fs';
|
import { join } from 'path';
|
||||||
import { dirname, join } from 'path';
|
import { appendFileSync } from 'fs';
|
||||||
|
|
||||||
import { InitArgs } from '../../init-v1';
|
import { InitArgs } from '../../init-v1';
|
||||||
import {
|
import { fileExists } from '../../../../utils/fileutils';
|
||||||
fileExists,
|
|
||||||
readJsonFile,
|
|
||||||
writeJsonFile,
|
|
||||||
} from '../../../../utils/fileutils';
|
|
||||||
import { output } from '../../../../utils/output';
|
import { output } from '../../../../utils/output';
|
||||||
import {
|
import {
|
||||||
detectPackageManager,
|
detectPackageManager,
|
||||||
getPackageManagerCommand,
|
getPackageManagerCommand,
|
||||||
PackageManagerCommands,
|
PackageManagerCommands,
|
||||||
} from '../../../../utils/package-manager';
|
} from '../../../../utils/package-manager';
|
||||||
import { PackageJson } from '../../../../utils/package-json';
|
|
||||||
import { checkForCustomWebpackSetup } from './check-for-custom-webpack-setup';
|
import { checkForCustomWebpackSetup } from './check-for-custom-webpack-setup';
|
||||||
import { checkForUncommittedChanges } from './check-for-uncommitted-changes';
|
|
||||||
import { cleanUpFiles } from './clean-up-files';
|
|
||||||
import { readNameFromPackageJson } from './read-name-from-package-json';
|
import { readNameFromPackageJson } from './read-name-from-package-json';
|
||||||
import { renameJsToJsx } from './rename-js-to-jsx';
|
import { renameJsToJsx } from './rename-js-to-jsx';
|
||||||
import { setupTsConfig } from './tsconfig-setup';
|
|
||||||
import { writeCracoConfig } from './write-craco-config';
|
|
||||||
import { writeViteConfig } from './write-vite-config';
|
import { writeViteConfig } from './write-vite-config';
|
||||||
import { writeViteIndexHtml } from './write-vite-index-html';
|
import { writeViteIndexHtml } from './write-vite-index-html';
|
||||||
import { connectExistingRepoToNxCloudPrompt } from '../../../connect/connect-to-nx-cloud';
|
|
||||||
|
|
||||||
type Options = InitArgs;
|
type Options = InitArgs;
|
||||||
|
|
||||||
@ -32,41 +23,52 @@ type NormalizedOptions = Options & {
|
|||||||
pmc: PackageManagerCommands;
|
pmc: PackageManagerCommands;
|
||||||
appIsJs: boolean;
|
appIsJs: boolean;
|
||||||
reactAppName: string;
|
reactAppName: string;
|
||||||
isCRA5: boolean;
|
|
||||||
npxYesFlagNeeded: boolean;
|
|
||||||
isVite: boolean;
|
|
||||||
isStandalone: boolean;
|
isStandalone: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export async function addNxToCraRepo(options: Options) {
|
export async function addNxToCraRepo(_options: Options) {
|
||||||
if (!options.force) {
|
if (!_options.force) {
|
||||||
checkForUncommittedChanges();
|
|
||||||
checkForCustomWebpackSetup();
|
checkForCustomWebpackSetup();
|
||||||
}
|
}
|
||||||
|
|
||||||
output.log({ title: '🐳 Nx initialization' });
|
const options = await normalizeOptions(_options);
|
||||||
|
|
||||||
const normalizedOptions = await normalizeOptions(options);
|
await addBundler(options);
|
||||||
await reorgnizeWorkspaceStructure(normalizedOptions);
|
|
||||||
|
appendFileSync(`.gitignore`, '\nnode_modules');
|
||||||
|
appendFileSync(`.gitignore`, '\ndist');
|
||||||
|
|
||||||
|
installDependencies(options);
|
||||||
|
|
||||||
|
// Vite expects index.html to be in the root as the main entry point.
|
||||||
|
const indexPath = options.isStandalone
|
||||||
|
? 'index.html'
|
||||||
|
: join('apps', options.reactAppName, 'index.html');
|
||||||
|
const oldIndexPath = options.isStandalone
|
||||||
|
? join('public', 'index.html')
|
||||||
|
: join('apps', options.reactAppName, 'public', 'index.html');
|
||||||
|
output.note({
|
||||||
|
title: `A new ${indexPath} has been created. Compare it to the previous ${oldIndexPath} file and make any changes needed, then delete the previous file.`,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (_options.force) {
|
||||||
|
output.note({
|
||||||
|
title: `Using --force converts projects with custom Webpack setup. You will need to manually update your vite.config.js file to match the plugins used in your old Webpack configuration.`,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function installDependencies(options: NormalizedOptions) {
|
function installDependencies(options: NormalizedOptions) {
|
||||||
const dependencies = [
|
const dependencies = [
|
||||||
|
'@rollup/plugin-replace',
|
||||||
'@testing-library/jest-dom',
|
'@testing-library/jest-dom',
|
||||||
|
'@vitejs/plugin-react',
|
||||||
'eslint-config-react-app',
|
'eslint-config-react-app',
|
||||||
'web-vitals',
|
'web-vitals',
|
||||||
'jest-watch-typeahead',
|
'jest-watch-typeahead',
|
||||||
|
'vite',
|
||||||
|
'vitest',
|
||||||
];
|
];
|
||||||
if (options.isVite) {
|
|
||||||
dependencies.push('vite', 'vitest', '@vitejs/plugin-react');
|
|
||||||
} else {
|
|
||||||
dependencies.push(
|
|
||||||
'@craco/craco',
|
|
||||||
'cross-env',
|
|
||||||
'react-scripts',
|
|
||||||
'tsconfig-paths-webpack-plugin'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
execSync(`${options.pmc.addDev} ${dependencies.join(' ')}`, {
|
execSync(`${options.pmc.addDev} ${dependencies.join(' ')}`, {
|
||||||
stdio: [0, 1, 2],
|
stdio: [0, 1, 2],
|
||||||
@ -77,282 +79,29 @@ function installDependencies(options: NormalizedOptions) {
|
|||||||
async function normalizeOptions(options: Options): Promise<NormalizedOptions> {
|
async function normalizeOptions(options: Options): Promise<NormalizedOptions> {
|
||||||
const packageManager = detectPackageManager();
|
const packageManager = detectPackageManager();
|
||||||
const pmc = getPackageManagerCommand(packageManager);
|
const pmc = getPackageManagerCommand(packageManager);
|
||||||
|
|
||||||
const appIsJs = !fileExists(`tsconfig.json`);
|
const appIsJs = !fileExists(`tsconfig.json`);
|
||||||
|
|
||||||
const reactAppName = readNameFromPackageJson();
|
const reactAppName = readNameFromPackageJson();
|
||||||
const packageJson = readJsonFile(join(process.cwd(), 'package.json'));
|
|
||||||
const deps = {
|
|
||||||
...packageJson.dependencies,
|
|
||||||
...packageJson.devDependencies,
|
|
||||||
};
|
|
||||||
const isCRA5 = /^[^~]?5/.test(deps['react-scripts']);
|
|
||||||
const npmVersion = execSync('npm -v', {
|
|
||||||
windowsHide: false,
|
|
||||||
}).toString();
|
|
||||||
// Should remove this check 04/2023 once Node 14 & npm 6 reach EOL
|
|
||||||
const npxYesFlagNeeded = !npmVersion.startsWith('6'); // npm 7 added -y flag to npx
|
|
||||||
const isVite = options.vite;
|
|
||||||
const isStandalone = !options.integrated;
|
const isStandalone = !options.integrated;
|
||||||
|
|
||||||
const nxCloud =
|
|
||||||
options.nxCloud ??
|
|
||||||
(options.interactive ? await connectExistingRepoToNxCloudPrompt() : false);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...options,
|
...options,
|
||||||
nxCloud,
|
|
||||||
packageManager,
|
packageManager,
|
||||||
pmc,
|
pmc,
|
||||||
appIsJs,
|
appIsJs,
|
||||||
reactAppName,
|
reactAppName,
|
||||||
isCRA5,
|
|
||||||
npxYesFlagNeeded,
|
|
||||||
isVite,
|
|
||||||
isStandalone,
|
isStandalone,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* - Create a temp workspace
|
|
||||||
* - Move all files to temp workspace
|
|
||||||
* - Add bundler to temp workspace
|
|
||||||
* - Move files back to root
|
|
||||||
* - Clean up unused files
|
|
||||||
*/
|
|
||||||
async function reorgnizeWorkspaceStructure(options: NormalizedOptions) {
|
|
||||||
createTempWorkspace(options);
|
|
||||||
|
|
||||||
moveFilesToTempWorkspace(options);
|
|
||||||
|
|
||||||
await addBundler(options);
|
|
||||||
|
|
||||||
output.log({ title: '🧶 Updating .gitignore file' });
|
|
||||||
|
|
||||||
execSync(`echo "node_modules" >> .gitignore`, {
|
|
||||||
stdio: [0, 1, 2],
|
|
||||||
windowsHide: false,
|
|
||||||
});
|
|
||||||
execSync(`echo "dist" >> .gitignore`, {
|
|
||||||
stdio: [0, 1, 2],
|
|
||||||
windowsHide: false,
|
|
||||||
});
|
|
||||||
|
|
||||||
process.chdir('..');
|
|
||||||
|
|
||||||
copyFromTempWorkspaceToRoot();
|
|
||||||
|
|
||||||
cleanUpUnusedFilesAndAddConfigFiles(options);
|
|
||||||
|
|
||||||
output.log({ title: '🙂 Please be patient, one final step remaining!' });
|
|
||||||
|
|
||||||
output.log({ title: '📦 Installing dependencies' });
|
|
||||||
installDependencies(options);
|
|
||||||
|
|
||||||
if (options.isVite) {
|
|
||||||
const indexPath = options.isStandalone
|
|
||||||
? 'index.html'
|
|
||||||
: join('apps', options.reactAppName, 'index.html');
|
|
||||||
const oldIndexPath = options.isStandalone
|
|
||||||
? join('public', 'index.html')
|
|
||||||
: join('apps', options.reactAppName, 'public', 'index.html');
|
|
||||||
output.note({
|
|
||||||
title: `A new ${indexPath} has been created. Compare it to the previous ${oldIndexPath} file and make any changes needed, then delete the previous file.`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function createTempWorkspace(options: NormalizedOptions) {
|
|
||||||
rmSync('temp-workspace', { recursive: true, force: true });
|
|
||||||
|
|
||||||
execSync(
|
|
||||||
`npx ${
|
|
||||||
options.npxYesFlagNeeded ? '-y' : ''
|
|
||||||
} create-nx-workspace@latest temp-workspace --appName=${
|
|
||||||
options.reactAppName
|
|
||||||
} --preset=react-monorepo --style=css --bundler=${
|
|
||||||
options.isVite ? 'vite' : 'webpack'
|
|
||||||
} --packageManager=${options.packageManager} ${
|
|
||||||
options.nxCloud ? '--nxCloud=yes' : '--nxCloud=skip'
|
|
||||||
} ${
|
|
||||||
options.addE2e ? '--e2eTestRunner=playwright' : '--e2eTestRunner=none'
|
|
||||||
}`,
|
|
||||||
{ stdio: [0, 1, 2], windowsHide: false }
|
|
||||||
);
|
|
||||||
|
|
||||||
output.log({ title: '👋 Welcome to Nx!' });
|
|
||||||
|
|
||||||
output.log({ title: '🧹 Clearing unused files' });
|
|
||||||
|
|
||||||
cpSync(
|
|
||||||
join('temp-workspace', 'apps', options.reactAppName, 'project.json'),
|
|
||||||
'project.json',
|
|
||||||
{ recursive: true }
|
|
||||||
);
|
|
||||||
rmSync(join('temp-workspace', 'apps', options.reactAppName), {
|
|
||||||
recursive: true,
|
|
||||||
force: true,
|
|
||||||
});
|
|
||||||
rmSync('node_modules', { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyPackageJsonDepsFromTempWorkspace() {
|
|
||||||
const repoRoot = process.cwd();
|
|
||||||
let rootPackageJson = readJsonFile(join(repoRoot, 'package.json'));
|
|
||||||
const tempWorkspacePackageJson = readJsonFile(
|
|
||||||
join(repoRoot, 'temp-workspace', 'package.json')
|
|
||||||
);
|
|
||||||
|
|
||||||
rootPackageJson = overridePackageDeps(
|
|
||||||
'dependencies',
|
|
||||||
rootPackageJson,
|
|
||||||
tempWorkspacePackageJson
|
|
||||||
);
|
|
||||||
rootPackageJson = overridePackageDeps(
|
|
||||||
'devDependencies',
|
|
||||||
rootPackageJson,
|
|
||||||
tempWorkspacePackageJson
|
|
||||||
);
|
|
||||||
rootPackageJson.scripts = {}; // remove existing scripts
|
|
||||||
writeJsonFile(join(repoRoot, 'package.json'), rootPackageJson);
|
|
||||||
writeJsonFile(
|
|
||||||
join(repoRoot, 'temp-workspace', 'package.json'),
|
|
||||||
rootPackageJson
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function overridePackageDeps(
|
|
||||||
depConfigName: 'dependencies' | 'devDependencies',
|
|
||||||
base: PackageJson,
|
|
||||||
override: PackageJson
|
|
||||||
): PackageJson {
|
|
||||||
if (!base[depConfigName]) {
|
|
||||||
base[depConfigName] = override[depConfigName];
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
const deps = override[depConfigName];
|
|
||||||
Object.keys(deps).forEach((dep) => {
|
|
||||||
if (base.dependencies?.[dep]) {
|
|
||||||
delete base.dependencies[dep];
|
|
||||||
}
|
|
||||||
if (base.devDependencies?.[dep]) {
|
|
||||||
delete base.devDependencies[dep];
|
|
||||||
}
|
|
||||||
base[depConfigName][dep] = deps[dep];
|
|
||||||
});
|
|
||||||
return base;
|
|
||||||
}
|
|
||||||
|
|
||||||
function moveSync(src: string, dest: string) {
|
|
||||||
const destParentDir = dirname(dest);
|
|
||||||
mkdirSync(destParentDir, { recursive: true });
|
|
||||||
rmSync(dest, { recursive: true, force: true });
|
|
||||||
return renameSync(src, dest);
|
|
||||||
}
|
|
||||||
|
|
||||||
function moveFilesToTempWorkspace(options: NormalizedOptions) {
|
|
||||||
output.log({ title: '🚚 Moving your React app in your new Nx workspace' });
|
|
||||||
|
|
||||||
copyPackageJsonDepsFromTempWorkspace();
|
|
||||||
const requiredCraFiles = [
|
|
||||||
'project.json',
|
|
||||||
'package.json',
|
|
||||||
'src',
|
|
||||||
'public',
|
|
||||||
options.appIsJs ? null : 'tsconfig.json',
|
|
||||||
options.packageManager === 'yarn' ? 'yarn.lock' : null,
|
|
||||||
options.packageManager === 'pnpm' ? 'pnpm-lock.yaml' : null,
|
|
||||||
options.packageManager === 'npm' ? 'package-lock.json' : null,
|
|
||||||
options.packageManager === 'bun' ? 'bun.lockb' : null,
|
|
||||||
];
|
|
||||||
|
|
||||||
const optionalCraFiles = ['README.md'];
|
|
||||||
|
|
||||||
const filesToMove = [...requiredCraFiles, ...optionalCraFiles].filter(
|
|
||||||
Boolean
|
|
||||||
);
|
|
||||||
|
|
||||||
filesToMove.forEach((f) => {
|
|
||||||
try {
|
|
||||||
moveSync(
|
|
||||||
f,
|
|
||||||
options.isStandalone
|
|
||||||
? join('temp-workspace', f)
|
|
||||||
: join('temp-workspace', 'apps', options.reactAppName, f)
|
|
||||||
);
|
|
||||||
} catch (error) {
|
|
||||||
if (requiredCraFiles.includes(f)) {
|
|
||||||
throw error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
process.chdir('temp-workspace');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function addBundler(options: NormalizedOptions) {
|
async function addBundler(options: NormalizedOptions) {
|
||||||
if (options.isVite) {
|
const { addViteCommandsToPackageScripts } = await import(
|
||||||
output.log({ title: '🧑🔧 Setting up Vite' });
|
'./add-vite-commands-to-package-scripts'
|
||||||
const { addViteCommandsToPackageScripts } = await import(
|
);
|
||||||
'./add-vite-commands-to-package-scripts'
|
addViteCommandsToPackageScripts(options.reactAppName, options.isStandalone);
|
||||||
);
|
writeViteConfig(options.reactAppName, options.isStandalone, options.appIsJs);
|
||||||
addViteCommandsToPackageScripts(options.reactAppName, options.isStandalone);
|
writeViteIndexHtml(
|
||||||
writeViteConfig(
|
options.reactAppName,
|
||||||
options.reactAppName,
|
options.isStandalone,
|
||||||
options.isStandalone,
|
options.appIsJs
|
||||||
options.appIsJs
|
);
|
||||||
);
|
await renameJsToJsx(options.reactAppName, options.isStandalone);
|
||||||
writeViteIndexHtml(
|
|
||||||
options.reactAppName,
|
|
||||||
options.isStandalone,
|
|
||||||
options.appIsJs
|
|
||||||
);
|
|
||||||
await renameJsToJsx(options.reactAppName, options.isStandalone);
|
|
||||||
} else {
|
|
||||||
output.log({ title: '🧑🔧 Setting up craco + Webpack' });
|
|
||||||
const { addCracoCommandsToPackageScripts } = await import(
|
|
||||||
'./add-craco-commands-to-package-scripts'
|
|
||||||
);
|
|
||||||
addCracoCommandsToPackageScripts(
|
|
||||||
options.reactAppName,
|
|
||||||
options.isStandalone
|
|
||||||
);
|
|
||||||
|
|
||||||
writeCracoConfig(
|
|
||||||
options.reactAppName,
|
|
||||||
options.isCRA5,
|
|
||||||
options.isStandalone
|
|
||||||
);
|
|
||||||
|
|
||||||
output.log({
|
|
||||||
title: '🛬 Skip CRA preflight check since Nx manages the monorepo',
|
|
||||||
});
|
|
||||||
|
|
||||||
execSync(`echo "SKIP_PREFLIGHT_CHECK=true" > .env`, {
|
|
||||||
stdio: [0, 1, 2],
|
|
||||||
windowsHide: false,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function copyFromTempWorkspaceToRoot() {
|
|
||||||
output.log({ title: '🚚 Folder restructuring.' });
|
|
||||||
|
|
||||||
readdirSync('temp-workspace').forEach((f) => {
|
|
||||||
moveSync(join('temp-workspace', f), f);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanUpUnusedFilesAndAddConfigFiles(options: NormalizedOptions) {
|
|
||||||
output.log({ title: '🧹 Cleaning up.' });
|
|
||||||
|
|
||||||
cleanUpFiles(options.reactAppName, options.isStandalone);
|
|
||||||
|
|
||||||
output.log({ title: "📃 Extend the app's tsconfig.json from the base" });
|
|
||||||
|
|
||||||
setupTsConfig(options.reactAppName, options.isStandalone);
|
|
||||||
|
|
||||||
if (options.isStandalone) {
|
|
||||||
rmSync('apps', { recursive: true, force: true });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,68 +0,0 @@
|
|||||||
import { writeFileSync } from 'fs';
|
|
||||||
|
|
||||||
export function writeCracoConfig(
|
|
||||||
appName: string,
|
|
||||||
isCRA5: boolean,
|
|
||||||
isStandalone: boolean
|
|
||||||
) {
|
|
||||||
const configOverride = `
|
|
||||||
const path = require('path');
|
|
||||||
const TsConfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
|
|
||||||
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
|
|
||||||
module.exports = {
|
|
||||||
webpack: {
|
|
||||||
configure: (config) => {
|
|
||||||
// Remove guard against importing modules outside of \`src\`.
|
|
||||||
// Needed for workspace projects.
|
|
||||||
config.resolve.plugins = config.resolve.plugins.filter(
|
|
||||||
(plugin) => !(plugin instanceof ModuleScopePlugin)
|
|
||||||
);
|
|
||||||
// Add support for importing workspace projects.
|
|
||||||
config.resolve.plugins.push(
|
|
||||||
new TsConfigPathsPlugin({
|
|
||||||
configFile: path.resolve(__dirname, 'tsconfig.json'),
|
|
||||||
extensions: ['.ts', '.tsx', '.js', '.jsx'],
|
|
||||||
mainFields: ['browser', 'module', 'main'],
|
|
||||||
})
|
|
||||||
);
|
|
||||||
${
|
|
||||||
isCRA5
|
|
||||||
? `
|
|
||||||
// Replace include option for babel loader with exclude
|
|
||||||
// so babel will handle workspace projects as well.
|
|
||||||
config.module.rules[1].oneOf.forEach((r) => {
|
|
||||||
if (r.loader && r.loader.indexOf('babel') !== -1) {
|
|
||||||
r.exclude = /node_modules/;
|
|
||||||
delete r.include;
|
|
||||||
}
|
|
||||||
});`
|
|
||||||
: `
|
|
||||||
// Replace include option for babel loader with exclude
|
|
||||||
// so babel will handle workspace projects as well.
|
|
||||||
config.module.rules.forEach((r) => {
|
|
||||||
if (r.oneOf) {
|
|
||||||
const babelLoader = r.oneOf.find(
|
|
||||||
(rr) => rr.loader.indexOf('babel-loader') !== -1
|
|
||||||
);
|
|
||||||
babelLoader.exclude = /node_modules/;
|
|
||||||
delete babelLoader.include;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
`
|
|
||||||
}
|
|
||||||
return config;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
jest: {
|
|
||||||
configure: (config) => {
|
|
||||||
config.resolver = '@nx/jest/plugins/resolver';
|
|
||||||
return config;
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
`;
|
|
||||||
writeFileSync(
|
|
||||||
isStandalone ? 'craco.config.js' : `apps/${appName}/craco.config.js`,
|
|
||||||
configOverride
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@ -5,7 +5,7 @@ export function writeViteConfig(
|
|||||||
isStandalone: boolean,
|
isStandalone: boolean,
|
||||||
isJs: boolean
|
isJs: boolean
|
||||||
) {
|
) {
|
||||||
let port = 4200;
|
let port = 3000;
|
||||||
|
|
||||||
// Use PORT from .env file if it exists in project.
|
// Use PORT from .env file if it exists in project.
|
||||||
if (existsSync(`../.env`)) {
|
if (existsSync(`../.env`)) {
|
||||||
@ -18,9 +18,21 @@ export function writeViteConfig(
|
|||||||
}
|
}
|
||||||
|
|
||||||
writeFileSync(
|
writeFileSync(
|
||||||
isStandalone ? 'vite.config.js' : `apps/${appName}/vite.config.js`,
|
isStandalone ? 'vite.config.mjs' : `apps/${appName}/vite.config.mjs`,
|
||||||
`import { defineConfig } from 'vite'
|
`import { defineConfig } from 'vite'
|
||||||
import react from '@vitejs/plugin-react'
|
import react from '@vitejs/plugin-react'
|
||||||
|
import replace from '@rollup/plugin-replace';
|
||||||
|
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||||
|
|
||||||
|
// Match CRA's environment variables.
|
||||||
|
// TODO: Replace these with VITE_ prefixed environment variables, and using import.meta.env.VITE_* instead of process.env.REACT_APP_*.
|
||||||
|
const craEnvVarRegex = /^REACT_APP/i;
|
||||||
|
const craEnvVars = Object.keys(process.env)
|
||||||
|
.filter((key) => craEnvVarRegex.test(key))
|
||||||
|
.reduce((env, key) => {
|
||||||
|
env[\`process.env.\${key}\`] = JSON.stringify(process.env[key]);
|
||||||
|
return env;
|
||||||
|
}, {});
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
@ -39,7 +51,11 @@ export default defineConfig({
|
|||||||
setupFiles: 'src/setupTests.${isJs ? 'js' : 'ts'}',
|
setupFiles: 'src/setupTests.${isJs ? 'js' : 'ts'}',
|
||||||
css: true,
|
css: true,
|
||||||
},
|
},
|
||||||
plugins: [react()],
|
plugins: [
|
||||||
|
react(),
|
||||||
|
replace({ values: craEnvVars, preventAssignment: true }),
|
||||||
|
nxViteTsPaths(),
|
||||||
|
],
|
||||||
});
|
});
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import { join } from 'path';
|
|||||||
|
|
||||||
import { NxJsonConfiguration } from '../../../config/nx-json';
|
import { NxJsonConfiguration } from '../../../config/nx-json';
|
||||||
import {
|
import {
|
||||||
|
directoryExists,
|
||||||
fileExists,
|
fileExists,
|
||||||
readJsonFile,
|
readJsonFile,
|
||||||
writeJsonFile,
|
writeJsonFile,
|
||||||
@ -336,3 +337,18 @@ export function isMonorepo(packageJson: PackageJson) {
|
|||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isCRA(packageJson: PackageJson) {
|
||||||
|
const combinedDependencies = {
|
||||||
|
...packageJson.dependencies,
|
||||||
|
...packageJson.devDependencies,
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
// Required dependencies for CRA projects
|
||||||
|
combinedDependencies['react'] &&
|
||||||
|
combinedDependencies['react-dom'] &&
|
||||||
|
combinedDependencies['react-scripts'] &&
|
||||||
|
directoryExists('src') &&
|
||||||
|
directoryExists('public')
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@ -8,7 +8,10 @@ import { readJsonFile } from '../../utils/fileutils';
|
|||||||
import { getPackageNameFromImportPath } from '../../utils/get-package-name-from-import-path';
|
import { getPackageNameFromImportPath } from '../../utils/get-package-name-from-import-path';
|
||||||
import { output } from '../../utils/output';
|
import { output } from '../../utils/output';
|
||||||
import { PackageJson } from '../../utils/package-json';
|
import { PackageJson } from '../../utils/package-json';
|
||||||
import { getPackageManagerCommand } from '../../utils/package-manager';
|
import {
|
||||||
|
detectPackageManager,
|
||||||
|
getPackageManagerCommand,
|
||||||
|
} from '../../utils/package-manager';
|
||||||
import { nxVersion } from '../../utils/versions';
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { globWithWorkspaceContextSync } from '../../utils/workspace-context';
|
import { globWithWorkspaceContextSync } from '../../utils/workspace-context';
|
||||||
import { connectExistingRepoToNxCloudPrompt } from '../connect/connect-to-nx-cloud';
|
import { connectExistingRepoToNxCloudPrompt } from '../connect/connect-to-nx-cloud';
|
||||||
@ -24,10 +27,12 @@ import { generateDotNxSetup } from './implementation/dot-nx/add-nx-scripts';
|
|||||||
import {
|
import {
|
||||||
createNxJsonFile,
|
createNxJsonFile,
|
||||||
initCloud,
|
initCloud,
|
||||||
|
isCRA,
|
||||||
isMonorepo,
|
isMonorepo,
|
||||||
printFinalMessage,
|
printFinalMessage,
|
||||||
updateGitIgnore,
|
updateGitIgnore,
|
||||||
} from './implementation/utils';
|
} from './implementation/utils';
|
||||||
|
import { addNxToCraRepo } from './implementation/react';
|
||||||
|
|
||||||
export interface InitArgs {
|
export interface InitArgs {
|
||||||
interactive: boolean;
|
interactive: boolean;
|
||||||
@ -35,6 +40,7 @@ export interface InitArgs {
|
|||||||
useDotNxInstallation?: boolean;
|
useDotNxInstallation?: boolean;
|
||||||
integrated?: boolean; // For Angular projects only
|
integrated?: boolean; // For Angular projects only
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
|
force?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function initHandler(options: InitArgs): Promise<void> {
|
export async function initHandler(options: InitArgs): Promise<void> {
|
||||||
@ -85,6 +91,7 @@ export async function initHandler(options: InitArgs): Promise<void> {
|
|||||||
const packageJson: PackageJson = readJsonFile('package.json');
|
const packageJson: PackageJson = readJsonFile('package.json');
|
||||||
const _isTurborepo = existsSync('turbo.json');
|
const _isTurborepo = existsSync('turbo.json');
|
||||||
const _isMonorepo = isMonorepo(packageJson);
|
const _isMonorepo = isMonorepo(packageJson);
|
||||||
|
const _isCRA = isCRA(packageJson);
|
||||||
|
|
||||||
const learnMoreLink = _isTurborepo
|
const learnMoreLink = _isTurborepo
|
||||||
? 'https://nx.dev/recipes/adopting-nx/from-turborepo'
|
? 'https://nx.dev/recipes/adopting-nx/from-turborepo'
|
||||||
@ -108,7 +115,18 @@ export async function initHandler(options: InitArgs): Promise<void> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_isMonorepo) {
|
const pmc = getPackageManagerCommand();
|
||||||
|
|
||||||
|
if (_isCRA) {
|
||||||
|
await addNxToCraRepo({
|
||||||
|
addE2e: false,
|
||||||
|
force: options.force,
|
||||||
|
vite: true,
|
||||||
|
integrated: false,
|
||||||
|
interactive: options.interactive,
|
||||||
|
nxCloud: false,
|
||||||
|
});
|
||||||
|
} else if (_isMonorepo) {
|
||||||
await addNxToMonorepo({
|
await addNxToMonorepo({
|
||||||
interactive: options.interactive,
|
interactive: options.interactive,
|
||||||
nxCloud: false,
|
nxCloud: false,
|
||||||
@ -125,7 +143,6 @@ export async function initHandler(options: InitArgs): Promise<void> {
|
|||||||
(options.interactive ? await connectExistingRepoToNxCloudPrompt() : false);
|
(options.interactive ? await connectExistingRepoToNxCloudPrompt() : false);
|
||||||
|
|
||||||
const repoRoot = process.cwd();
|
const repoRoot = process.cwd();
|
||||||
const pmc = getPackageManagerCommand();
|
|
||||||
|
|
||||||
createNxJsonFile(repoRoot, [], [], {});
|
createNxJsonFile(repoRoot, [], [], {});
|
||||||
updateGitIgnore(repoRoot);
|
updateGitIgnore(repoRoot);
|
||||||
@ -134,10 +151,18 @@ export async function initHandler(options: InitArgs): Promise<void> {
|
|||||||
|
|
||||||
output.log({ title: '🧐 Checking dependencies' });
|
output.log({ title: '🧐 Checking dependencies' });
|
||||||
|
|
||||||
const { plugins, updatePackageScripts } = await detectPlugins(
|
let plugins: string[];
|
||||||
nxJson,
|
let updatePackageScripts: boolean;
|
||||||
options.interactive
|
|
||||||
);
|
if (_isCRA) {
|
||||||
|
plugins = ['@nx/vite'];
|
||||||
|
updatePackageScripts = true;
|
||||||
|
} else {
|
||||||
|
const { plugins: _plugins, updatePackageScripts: _updatePackageScripts } =
|
||||||
|
await detectPlugins(nxJson, options.interactive);
|
||||||
|
plugins = _plugins;
|
||||||
|
updatePackageScripts = _updatePackageScripts;
|
||||||
|
}
|
||||||
|
|
||||||
output.log({ title: '📦 Installing Nx' });
|
output.log({ title: '📦 Installing Nx' });
|
||||||
|
|
||||||
|
|||||||
@ -48,6 +48,7 @@ export interface nxViteTsPathsOptions {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function nxViteTsPaths(options: nxViteTsPathsOptions = {}) {
|
export function nxViteTsPaths(options: nxViteTsPathsOptions = {}) {
|
||||||
|
let foundTsConfigPath: string;
|
||||||
let matchTsPathEsm: MatchPath;
|
let matchTsPathEsm: MatchPath;
|
||||||
let matchTsPathFallback: MatchPath | undefined;
|
let matchTsPathFallback: MatchPath | undefined;
|
||||||
let tsConfigPathsEsm: ConfigLoaderSuccessResult;
|
let tsConfigPathsEsm: ConfigLoaderSuccessResult;
|
||||||
@ -79,7 +80,7 @@ export function nxViteTsPaths(options: nxViteTsPathsOptions = {}) {
|
|||||||
async configResolved(config: any) {
|
async configResolved(config: any) {
|
||||||
projectRoot = config.root;
|
projectRoot = config.root;
|
||||||
const projectRootFromWorkspaceRoot = relative(workspaceRoot, projectRoot);
|
const projectRootFromWorkspaceRoot = relative(workspaceRoot, projectRoot);
|
||||||
let foundTsConfigPath = getTsConfig(
|
foundTsConfigPath = getTsConfig(
|
||||||
process.env.NX_TSCONFIG_PATH ??
|
process.env.NX_TSCONFIG_PATH ??
|
||||||
join(
|
join(
|
||||||
workspaceRoot,
|
workspaceRoot,
|
||||||
@ -89,10 +90,8 @@ export function nxViteTsPaths(options: nxViteTsPathsOptions = {}) {
|
|||||||
'tsconfig.generated.json'
|
'tsconfig.generated.json'
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
if (!foundTsConfigPath) {
|
|
||||||
throw new Error(stripIndents`Unable to find a tsconfig in the workspace!
|
if (!foundTsConfigPath) return;
|
||||||
There should at least be a tsconfig.base.json or tsconfig.json in the root of the workspace ${workspaceRoot}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!options.buildLibsFromSource &&
|
!options.buildLibsFromSource &&
|
||||||
@ -164,6 +163,9 @@ There should at least be a tsconfig.base.json or tsconfig.json in the root of th
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
resolveId(importPath: string) {
|
resolveId(importPath: string) {
|
||||||
|
// Let other resolvers handle this path.
|
||||||
|
if (!foundTsConfigPath) return null;
|
||||||
|
|
||||||
let resolvedFile: string;
|
let resolvedFile: string;
|
||||||
try {
|
try {
|
||||||
resolvedFile = matchTsPathEsm(importPath);
|
resolvedFile = matchTsPathEsm(importPath);
|
||||||
@ -211,6 +213,7 @@ There should at least be a tsconfig.base.json or tsconfig.json in the root of th
|
|||||||
resolve(preferredTsConfigPath),
|
resolve(preferredTsConfigPath),
|
||||||
resolve(join(workspaceRoot, 'tsconfig.base.json')),
|
resolve(join(workspaceRoot, 'tsconfig.base.json')),
|
||||||
resolve(join(workspaceRoot, 'tsconfig.json')),
|
resolve(join(workspaceRoot, 'tsconfig.json')),
|
||||||
|
resolve(join(workspaceRoot, 'jsconfig.json')),
|
||||||
].find((tsPath) => {
|
].find((tsPath) => {
|
||||||
if (existsSync(tsPath)) {
|
if (existsSync(tsPath)) {
|
||||||
logIt('Found tsconfig at', tsPath);
|
logIt('Found tsconfig at', tsPath);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user