cleanup(misc): redirect to nx init when running cra-to-nx (#15568)

This commit is contained in:
Leosvel Pérez Espinosa 2023-03-10 08:19:03 +00:00 committed by GitHub
parent ad12ab2ed3
commit 29be9dbaee
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 12 additions and 807 deletions

View File

@ -0,0 +1,8 @@
#!/usr/bin/env node
import { execSync } from 'child_process';
const args = process.argv.slice(2).join(' ');
execSync(`npx --yes nx@latest init ${args}`, {
stdio: [0, 1, 2],
});

View File

@ -15,20 +15,13 @@
"CLI"
],
"bin": {
"cra-to-nx": "src/index.js"
"cra-to-nx": "./index.js"
},
"license": "MIT",
"bugs": {
"url": "https://github.com/nrwl/nx/issues"
},
"homepage": "https://nx.dev",
"dependencies": {
"fs-extra": "^11.1.0",
"glob": "7.1.4",
"nx": "file:../nx",
"tslib": "^2.3.0",
"yargs": "^17.6.2"
},
"publishConfig": {
"access": "public"
}

View File

@ -1,7 +1,7 @@
{
"name": "cra-to-nx",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"sourceRoot": "packages/cra-to-nx/src",
"sourceRoot": "packages/cra-to-nx",
"projectType": "library",
"targets": {
"lint": {},
@ -9,7 +9,7 @@
"build-base": {
"executor": "@nrwl/js:tsc",
"options": {
"main": "packages/cra-to-nx/src/index.ts",
"main": "packages/cra-to-nx/index.ts",
"assets": [
"packages/cra-to-nx/*.md",
"packages/cra-to-nx/package.json",
@ -27,7 +27,7 @@
"options": {
"commands": [
{
"command": "node ./scripts/chmod build/packages/cra-to-nx/src/index.js"
"command": "node ./scripts/chmod build/packages/cra-to-nx/index.js"
},
{
"command": "node ./scripts/copy-readme.js cra-to-nx"

View File

@ -1,41 +0,0 @@
#!/usr/bin/env node
import * as yargs from 'yargs';
import { createNxWorkspaceForReact } from './lib/cra-to-nx';
export * from './lib/cra-to-nx';
export const commandsObject = yargs
.parserConfiguration({ 'strip-dashed': true })
.option('force', {
type: 'boolean',
describe: 'Skip validation and run the migration.',
default: false,
})
.option('e2e', {
type: 'boolean',
describe: 'Generate end-to-end tests with Cypress.',
default: false,
})
.option('nxCloud', {
type: 'boolean',
describe: 'Setup Nx Cloud.',
default: true,
})
.option('vite', {
type: 'boolean',
describe:
'Use Vite and Vitest (instead of Webpack and Jest). Pass --vite=false to use Webpack.',
default: true,
})
.option('integrated', {
type: 'boolean',
describe: 'Use integrated folder structure, with apps folder.',
default: false,
})
.help();
createNxWorkspaceForReact(commandsObject.argv).catch((e) => {
console.log(e);
process.exit(1);
});

View File

@ -1,22 +0,0 @@
import { readJsonFile, writeJsonFile } from 'nx/src/utils/fileutils';
export function addCracoCommandsToPackageScripts(
appName: string,
isStandalone: boolean
) {
const packageJsonPath = isStandalone
? 'package.json'
: `apps/${appName}/package.json`;
const distPath = isStandalone
? `dist/${appName}`
: `../../dist/apps/${appName}`;
const packageJson = readJsonFile(packageJsonPath);
packageJson.scripts = {
...packageJson.scripts,
start: 'nx exec -- craco start',
serve: 'npm start',
build: `cross-env BUILD_PATH=${distPath} nx exec -- craco build`,
test: 'nx exec -- craco test',
};
writeJsonFile(packageJsonPath, packageJson);
}

View File

@ -1,19 +0,0 @@
import { readJsonFile, writeJsonFile } from 'nx/src/utils/fileutils';
export function addViteCommandsToPackageScripts(
appName: string,
isStandalone: boolean
) {
const packageJsonPath = isStandalone
? 'package.json'
: `apps/${appName}/package.json`;
const packageJson = readJsonFile(packageJsonPath);
packageJson.scripts = {
...packageJson.scripts,
start: 'nx exec -- vite',
serve: 'nx exec -- vite',
build: `nx exec -- vite build`,
test: 'nx exec -- vitest',
};
writeJsonFile(packageJsonPath, packageJson, { spaces: 2 });
}

View File

@ -1,17 +0,0 @@
import { readJsonFile } from 'nx/src/utils/fileutils';
export function checkForCustomWebpackSetup() {
const packageJson = readJsonFile('package.json');
const combinedDeps = {
...packageJson.dependencies,
...packageJson.devDependencies,
};
['react-app-rewired', '@craco/craco'].forEach((pkg) => {
if (combinedDeps[pkg]) {
console.log(
`Skipping migration due to custom webpack setup. Found "${pkg}" usage. Use --force to continue anyway.`
);
process.exit(1);
}
});
}

View File

@ -1,13 +0,0 @@
import { execSync } from 'child_process';
export function checkForUncommittedChanges() {
const gitResult = execSync(`git status --porcelain`);
if (gitResult.length > 0) {
console.log('❗️ Careful!');
console.log('You have uncommited changes in your repository.');
console.log('');
console.log(gitResult.toString());
console.log('Please commit your changes before running the migrator!');
process.exit(1);
}
}

View File

@ -1,33 +0,0 @@
import { removeSync } from 'fs-extra';
import { readJsonFile, writeJsonFile } from 'nx/src/utils/fileutils';
export function cleanUpFiles(appName: string, isStandalone: boolean) {
// Delete targets from project since we delegate to npm scripts.
const projectJsonPath = isStandalone
? 'project.json'
: `apps/${appName}/project.json`;
const json = readJsonFile(projectJsonPath);
delete json.targets;
if (isStandalone) {
if (json.sourceRoot) {
json.sourceRoot = json.sourceRoot.replace(`apps/${appName}/`, '');
}
if (json['$schema']) {
json['$schema'] = json['$schema'].replace(
'../../node_modules',
'node_modules'
);
}
}
writeJsonFile(projectJsonPath, json);
removeSync('temp-workspace');
if (isStandalone) {
removeSync('babel.config.json');
removeSync('jest.preset.js');
removeSync('jest.config.ts');
removeSync('libs');
removeSync('tools');
}
}

View File

@ -1,317 +0,0 @@
import { execSync } from 'child_process';
import { join } from 'path';
import { copySync, moveSync, readdirSync, removeSync } from 'fs-extra';
import { fileExists, readJsonFile } from 'nx/src/utils/fileutils';
import { output } from 'nx/src/utils/output';
import {
detectPackageManager,
getPackageManagerCommand,
PackageManagerCommands,
} from 'nx/src/utils/package-manager';
import { checkForUncommittedChanges } from './check-for-uncommitted-changes';
import { setupE2eProject } from './setup-e2e-project';
import { readNameFromPackageJson } from './read-name-from-package-json';
import { setupTsConfig } from './tsconfig-setup';
import { writeCracoConfig } from './write-craco-config';
import { cleanUpFiles } from './clean-up-files';
import { writeViteConfig } from './write-vite-config';
import { renameJsToJsx } from './rename-js-to-jsx';
import { writeViteIndexHtml } from './write-vite-index-html';
import { checkForCustomWebpackSetup } from './check-for-custom-webpack-setup';
export interface Options {
force: boolean;
e2e: boolean;
nxCloud: boolean;
vite: boolean;
integrated: boolean;
}
interface NormalizedOptions extends Options {
packageManager: string;
pmc: PackageManagerCommands;
appIsJs: boolean;
reactAppName: string;
isCRA5: boolean;
npxYesFlagNeeded: boolean;
isVite: boolean;
isStandalone: boolean;
}
function addDependencies(pmc: PackageManagerCommands, ...deps: string[]) {
const depsArg = deps.join(' ');
output.log({ title: `📦 Adding dependencies: ${depsArg}` });
execSync(`${pmc.addDev} ${depsArg}`, { stdio: [0, 1, 2] });
}
function removeDependencies(pmc: PackageManagerCommands, ...deps: string[]) {
const depsArg = deps.join(' ');
output.log({ title: `📦 Removing dependencies: ${depsArg}` });
execSync(`${pmc.rm} ${depsArg}`, { stdio: [0, 1, 2] });
}
export function normalizeOptions(options: Options): NormalizedOptions {
const packageManager = detectPackageManager();
const pmc = getPackageManagerCommand(packageManager);
const appIsJs = !fileExists(`tsconfig.json`);
const reactAppName = readNameFromPackageJson();
const packageJson = readJsonFile('package.json');
const deps = {
...packageJson.dependencies,
...packageJson.devDependencies,
};
const isCRA5 = /^[^~]?5/.test(deps['react-scripts']);
const npmVersion = execSync('npm -v').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;
return {
...options,
packageManager,
pmc,
appIsJs,
reactAppName,
isCRA5,
npxYesFlagNeeded,
isVite,
isStandalone,
};
}
export async function createNxWorkspaceForReact(options: Record<string, any>) {
if (!options.force) {
checkForUncommittedChanges();
checkForCustomWebpackSetup();
}
output.log({ title: '✨ Nx initialization' });
const normalizedOptions = normalizeOptions(options as Options);
await reorgnizeWorkspaceStructure(normalizedOptions);
}
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] });
execSync(`echo "dist" >> .gitignore`, { stdio: [0, 1, 2] });
process.chdir('..');
copyFromTempWorkspaceToRoot();
cleanUpUnusedFilesAndAddConfigFiles(options);
output.log({ title: '🙂 Please be patient, one final step remaining!' });
output.log({
title: '🧶 Adding npm packages to your new Nx workspace',
});
addDependencies(
options.pmc,
'@testing-library/jest-dom',
'eslint-config-react-app',
'web-vitals',
'jest-watch-typeahead'
);
if (options.isVite) {
addDependencies(options.pmc, 'vite', 'vitest', '@vitejs/plugin-react');
} else {
addDependencies(
options.pmc,
'@craco/craco',
'cross-env',
'react-scripts',
'tsconfig-paths-webpack-plugin'
);
}
output.log({ title: '🎉 Done!' });
output.note({
title: 'First time using Nx? Check out this interactive Nx tutorial.',
bodyLines: [
`https://nx.dev/react-tutorial/1-code-generation`,
` `,
`Prefer watching videos? Check out this free Nx course on Egghead.io.`,
`https://egghead.io/playlists/scale-react-development-with-nx-4038`,
],
});
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.`,
});
}
output.note({
title: 'Or, you can try the commands!',
bodyLines: [
options.integrated ? `npx nx serve ${options.reactAppName}` : 'npm start',
options.integrated
? `npx nx build ${options.reactAppName}`
: 'npm run build',
options.integrated ? `npx nx test ${options.reactAppName}` : `npm test`,
` `,
`https://nx.dev/getting-started/intro#10-try-the-commands`,
],
});
}
function createTempWorkspace(options: NormalizedOptions) {
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' : '--nxCloud=false'
}`,
{ stdio: [0, 1, 2] }
);
output.log({ title: '👋 Welcome to Nx!' });
output.log({ title: '🧹 Clearing unused files' });
copySync(
join('temp-workspace', 'apps', options.reactAppName, 'project.json'),
'project.json'
);
removeSync(join('temp-workspace', 'apps', options.reactAppName));
removeSync('node_modules');
}
function moveFilesToTempWorkspace(options: NormalizedOptions) {
output.log({ title: '🚚 Moving your React app in your new Nx workspace' });
const requiredCraFiles = [
'project.json',
options.isStandalone ? null : '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,
];
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),
{
overwrite: true,
}
);
} catch (error) {
if (requiredCraFiles.includes(f)) {
throw error;
}
}
});
process.chdir('temp-workspace');
}
async function addBundler(options: NormalizedOptions) {
if (options.isVite) {
output.log({ title: '🧑‍🔧 Setting up Vite' });
const { addViteCommandsToPackageScripts } = await import(
'./add-vite-commands-to-package-scripts'
);
addViteCommandsToPackageScripts(options.reactAppName, options.isStandalone);
writeViteConfig(
options.reactAppName,
options.isStandalone,
options.appIsJs
);
writeViteIndexHtml(
options.reactAppName,
options.isStandalone,
options.appIsJs
);
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] });
}
}
function copyFromTempWorkspaceToRoot() {
output.log({ title: '🚚 Folder restructuring.' });
readdirSync('temp-workspace').forEach((f) => {
moveSync(join('temp-workspace', f), f, { overwrite: true });
});
}
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.e2e && !options.isStandalone) {
output.log({ title: '📃 Setup e2e tests' });
setupE2eProject(options.reactAppName);
} else {
removeSync(join('apps', `${options.reactAppName}-e2e`));
execSync(`${options.pmc.rm} @nrwl/cypress eslint-plugin-cypress`);
}
if (options.isStandalone) {
removeSync('apps');
}
}

View File

@ -1,16 +0,0 @@
import { fileExists, readJsonFile } from 'nx/src/utils/fileutils';
export function readNameFromPackageJson(): string {
let appName = 'webapp';
if (fileExists('package.json')) {
const json = readJsonFile('package.json');
if (
json['name'] &&
json['name'].length &&
json['name'].replace(/\s/g, '').length
) {
appName = json['name'].replace(/\s/g, '');
}
}
return appName;
}

View File

@ -1,18 +0,0 @@
import { sync } from 'glob';
import { renameSync, readFileSync } from 'fs-extra';
// Vite cannot process JSX like <div> or <Header> unless the file is named .jsx or .tsx
export function renameJsToJsx(appName: string, isStandalone: boolean) {
const files = sync(
isStandalone ? 'src/**/*.js' : `apps/${appName}/src/**/*.js`
);
files.forEach((file) => {
const content = readFileSync(file).toString();
// Try to detect JSX before renaming to .jsx
// Files like setupTests.js from CRA should not be renamed
if (/<[a-zA-Z0-9]+/.test(content)) {
renameSync(file, `${file}x`);
}
});
}

View File

@ -1,46 +0,0 @@
import {
fileExists,
readJsonFile,
writeJsonFile,
} from 'nx/src/utils/fileutils';
import { writeFileSync } from 'fs';
export function setupE2eProject(appName: string) {
const json = readJsonFile(`apps/${appName}-e2e/project.json`);
json.targets.e2e = {
executor: 'nx:run-commands',
options: {
commands: [`nx e2e-serve ${appName}-e2e`, `nx e2e-run ${appName}-e2e`],
},
};
json.targets['e2e-run'] = {
executor: '@nrwl/cypress:cypress',
options: {
cypressConfig: `apps/${appName}-e2e/cypress.json`,
tsConfig: `apps/${appName}-e2e/tsconfig.e2e.json`,
baseUrl: 'http://localhost:3000',
},
};
json.targets['e2e-serve'] = {
executor: 'nx:run-commands',
options: {
commands: [`nx serve ${appName}`],
readyWhen: 'can now view',
},
};
writeJsonFile(`apps/${appName}-e2e/project.json`, json);
if (fileExists(`apps/${appName}-e2e/src/integration/app.spec.ts`)) {
const integrationE2eTest = `
describe('${appName}', () => {
beforeEach(() => cy.visit('/'));
it('should contain a body', () => {
cy.get('body').should('exist');
});
});`;
writeFileSync(
`apps/${appName}-e2e/src/integration/app.spec.ts`,
integrationE2eTest
);
}
}

View File

@ -1,111 +0,0 @@
import {
fileExists,
readJsonFile,
writeJsonFile,
} from 'nx/src/utils/fileutils';
import { join } from 'path';
const defaultTsConfig = (relativePathToRoot: string) => ({
extends: relativePathToRoot
? join(relativePathToRoot, 'tsconfig.base.json')
: './tsconfig.base.json',
compilerOptions: {
jsx: 'react',
allowJs: true,
esModuleInterop: true,
allowSyntheticDefaultImports: true,
},
files: [],
include: [],
references: [
{
path: './tsconfig.app.json',
},
{
path: './tsconfig.spec.json',
},
],
});
const defaultTsConfigApp = (relativePathToRoot: string) => ({
extends: './tsconfig.json',
compilerOptions: {
outDir: join(relativePathToRoot, 'dist/out-tsc'),
types: ['node'],
},
files: [
join(relativePathToRoot, 'node_modules/@nrwl/react/typings/cssmodule.d.ts'),
join(relativePathToRoot, 'node_modules/@nrwl/react/typings/image.d.ts'),
],
exclude: ['**/*.spec.ts', '**/*.spec.tsx'],
include: ['**/*.js', '**/*.jsx', '**/*.ts', '**/*.tsx'],
});
const defaultTsConfigSpec = (relativePathToRoot: string) => ({
extends: './tsconfig.json',
compilerOptions: {
outDir: join(relativePathToRoot, 'dist/out-tsc'),
module: 'commonjs',
types: ['jest', 'node'],
},
include: [
'**/*.spec.ts',
'**/*.spec.tsx',
'**/*.spec.js',
'**/*.spec.jsx',
'**/*.d.ts',
],
files: [
join(relativePathToRoot, 'node_modules/@nrwl/react/typings/cssmodule.d.ts'),
join(relativePathToRoot, 'node_modules/@nrwl/react/typings/image.d.ts'),
],
});
export function setupTsConfig(appName: string, isStandalone: boolean) {
const tsconfigPath = isStandalone
? 'tsconfig.json'
: `apps/${appName}/tsconfig.json`;
const tsconfigAppPath = isStandalone
? 'tsconfig.app.json'
: `apps/${appName}/tsconfig.app.json`;
const tsconfiSpecPath = isStandalone
? 'tsconfig.spec.json'
: `apps/${appName}/tsconfig.spec.json`;
const tsconfigBasePath = isStandalone
? './tsconfig.base.json'
: '../../tsconfig.base.json';
const relativePathToRoot = isStandalone ? '' : '../../';
if (fileExists(tsconfigPath)) {
const json = readJsonFile(tsconfigPath);
json.extends = tsconfigBasePath;
if (json.compilerOptions) {
json.compilerOptions.jsx = 'react';
} else {
json.compilerOptions = {
jsx: 'react',
allowJs: true,
esModuleInterop: true,
allowSyntheticDefaultImports: true,
};
}
writeJsonFile(tsconfigPath, json);
} else {
writeJsonFile(tsconfigPath, defaultTsConfig(relativePathToRoot));
}
if (fileExists(tsconfigAppPath)) {
const json = readJsonFile(tsconfigAppPath);
json.extends = './tsconfig.json';
writeJsonFile(tsconfigAppPath, json);
} else {
writeJsonFile(tsconfigAppPath, defaultTsConfigApp(relativePathToRoot));
}
if (fileExists(tsconfiSpecPath)) {
const json = readJsonFile(tsconfiSpecPath);
json.extends = './tsconfig.json';
writeJsonFile(tsconfiSpecPath, json);
} else {
writeJsonFile(tsconfiSpecPath, defaultTsConfigSpec(relativePathToRoot));
}
}

View File

@ -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 = '@nrwl/jest/plugins/resolver';
return config;
},
},
};
`;
writeFileSync(
isStandalone ? 'craco.config.js' : `apps/${appName}/craco.config.js`,
configOverride
);
}

View File

@ -1,46 +0,0 @@
import * as fs from 'fs';
export function writeViteConfig(
appName: string,
isStandalone: boolean,
isJs: boolean
) {
let port = 4200;
// Use PORT from .env file if it exists in project.
if (fs.existsSync(`../.env`)) {
const envFile = fs.readFileSync(`../.env`).toString();
const result = envFile.match(/\bport=(?<port>\d{4})/i);
const portCandidate = Number(result?.groups?.port);
if (!isNaN(portCandidate)) {
port = portCandidate;
}
}
fs.writeFileSync(
isStandalone ? 'vite.config.js' : `apps/${appName}/vite.config.js`,
`import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
// https://vitejs.dev/config/
export default defineConfig({
build: {
outDir: ${
isStandalone ? `'./dist/${appName}'` : `'../../dist/apps/${appName}'`
}
},
server: {
port: ${port},
open: true,
},
test: {
globals: true,
environment: 'jsdom',
setupFiles: 'src/setupTests.${isJs ? 'js' : 'ts'}',
css: true,
},
plugins: [react()],
});
`
);
}

View File

@ -1,29 +0,0 @@
import * as fs from 'fs';
export function writeViteIndexHtml(
appName: string,
isStandalone: boolean,
isJs: boolean
) {
const indexPath = isStandalone ? 'index.html' : `apps/${appName}/index.html`;
if (fs.existsSync(indexPath)) {
fs.copyFileSync(indexPath, indexPath + '.old');
}
const indexFile = isJs ? '/src/index.jsx' : '/src/index.tsx';
fs.writeFileSync(
indexPath,
`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + React + Nx</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="${indexFile}"></script>
</body>
</html>`
);
}