feat(vite): update vite-tsconfig-paths (#13714)

This commit is contained in:
Katerina Skroumpelou 2022-12-08 20:36:45 +02:00 committed by GitHub
parent e470b6e259
commit 45ce3b2a0a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 378 additions and 39 deletions

File diff suppressed because one or more lines are too long

View File

@ -178,7 +178,6 @@ export default defineConfig({
react(),
ViteTsConfigPathsPlugin({
root: '../../',
projects: ['tsconfig.base.json'],
}),
],
});
@ -221,7 +220,6 @@ export default mergeConfig(baseConfig, {
react(),
ViteTsConfigPathsPlugin({
root: '../../',
projects: ['tsconfig.base.json'],
}),
],
});

View File

@ -1 +1,21 @@
{}
{
"schematics": {
"update-vite-tsconfig-paths": {
"cli": "nx",
"version": "15.3.1-beta.0",
"description": "Update vite-tsconfig-paths to 4.0.1 and remove projects property from vite.config.ts.",
"factory": "./src/migrations/update-15-3-1/update-vite-tsconfig-paths"
}
},
"packageJsonUpdates": {
"15.3.1-beta.0": {
"version": "15.3.1-beta.0",
"packages": {
"vite-tsconfig-paths": {
"version": "^4.0.1",
"alwaysAddToPackageJson": true
}
}
}
}
}

View File

@ -0,0 +1,12 @@
import path = require('path');
import json = require('./migrations.json');
describe('Vite migrations', () => {
it('should have valid paths', () => {
Object.values(json.schematics).forEach((m) => {
expect(() =>
require.resolve(path.join(__dirname, `${m.factory}.ts`))
).not.toThrow();
});
});
});

View File

@ -13,7 +13,7 @@ Object {
"jsdom": "~20.0.3",
"vite": "^3.0.5",
"vite-plugin-eslint": "^1.6.0",
"vite-tsconfig-paths": "^3.5.2",
"vite-tsconfig-paths": "^4.0.1",
"vitest": "^0.25.1",
},
"name": "test-name",

View File

@ -106,7 +106,7 @@ describe('vitest generator', () => {
/// <reference types=\\"vitest\\" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
@ -118,9 +118,8 @@ describe('vitest generator', () => {
plugins: [
react(),
tsconfigPaths({
viteTsConfigPaths({
root: '../../',
projects: ['tsconfig.base.json'],
}),
],
@ -150,7 +149,7 @@ describe('vitest generator', () => {
/// <reference types=\\"vitest\\" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import viteTsConfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
@ -162,9 +161,8 @@ describe('vitest generator', () => {
plugins: [
react(),
tsconfigPaths({
viteTsConfigPaths({
root: '../../',
projects: ['tsconfig.base.json'],
}),
],

View File

@ -0,0 +1,35 @@
import { addDependenciesToPackageJson, Tree } from '@nrwl/devkit';
import { createTreeWithEmptyV1Workspace } from '@nrwl/devkit/testing';
import { mockViteReactAppGenerator } from '../../utils/test-utils';
import {
getTsSourceFile,
removeProjectsFromViteTsConfigPaths,
} from './update-vite-tsconfig-paths';
describe('remove projects from vite-tsconfig-paths', () => {
let tree: Tree;
beforeEach(() => {
tree = createTreeWithEmptyV1Workspace();
mockViteReactAppGenerator(tree);
const existing = 'existing';
const existingVersion = '1.0.0';
addDependenciesToPackageJson(
tree,
{ 'vite-tsconfig-paths': '^3.6.0', [existing]: existingVersion },
{ [existing]: existingVersion }
);
});
it('should remove the projects attribute from vite-tsconfig-paths', async () => {
await removeProjectsFromViteTsConfigPaths(tree);
const file = getTsSourceFile(
tree,
'apps/my-test-react-vite-app/vite.config.ts'
);
expect(file.getText().includes('tsconfig.base.json')).toBeFalsy();
expect(file.getText().includes('projects')).toBeFalsy();
});
});

View File

@ -0,0 +1,100 @@
import {
applyChangesToString,
ChangeType,
formatFiles,
joinPathFragments,
readProjectConfiguration,
Tree,
workspaceRoot,
} from '@nrwl/devkit';
import { forEachExecutorOptions } from '@nrwl/workspace/src/utilities/executor-options-utils';
import { findNodes } from 'nx/src/utils/typescript';
import ts = require('typescript');
export async function removeProjectsFromViteTsConfigPaths(tree: Tree) {
findAllProjectsWithViteConfig(tree);
await formatFiles(tree);
}
function findAllProjectsWithViteConfig(tree: Tree): void {
forEachExecutorOptions(tree, '@nrwl/vite:build', (options, project) => {
const projectConfiguration = readProjectConfiguration(tree, project);
const viteConfig = normalizeConfigFilePathWithTree(
tree,
projectConfiguration.root,
options?.['configFile'],
workspaceRoot
);
if (viteConfig) {
const file = getTsSourceFile(tree, viteConfig);
const appFileContent = tree.read(viteConfig, 'utf-8');
let newContents = appFileContent;
const defineConfig = findNodes(file, [ts.SyntaxKind.CallExpression]);
let startOfProjects, endOfProjects;
defineConfig.forEach((node) => {
if (node.getText().startsWith('defineConfig')) {
node.getChildren().forEach((defineConfigContentNode) => {
// Make sure it's the one we are looking for
// We cannot assume that it's called tsConfigPaths
// So make sure it includes `projects` and `root`
if (
defineConfigContentNode.getText().includes('projects') &&
defineConfigContentNode.getText().includes('root')
) {
findNodes(defineConfigContentNode, [
ts.SyntaxKind.PropertyAssignment,
]).forEach((nodePA) => {
if (nodePA.getText().startsWith('projects')) {
startOfProjects = nodePA.getStart();
endOfProjects = nodePA.getEnd();
}
});
}
});
}
});
if (startOfProjects && endOfProjects) {
newContents = applyChangesToString(newContents, [
{
type: ChangeType.Delete,
start: startOfProjects,
length: endOfProjects - startOfProjects + 1,
},
]);
tree.write(viteConfig, newContents);
}
}
});
}
export function getTsSourceFile(host: Tree, path: string): ts.SourceFile {
const buffer = host.read(path);
if (!buffer) {
throw new Error(`Could not read TS file (${path}).`);
}
const content = buffer.toString();
const source = ts.createSourceFile(
path,
content,
ts.ScriptTarget.Latest,
true
);
return source;
}
function normalizeConfigFilePathWithTree(
tree: Tree,
projectRoot: string,
configFile?: string,
workspaceRoot?: string
): string {
return configFile
? joinPathFragments(`${workspaceRoot}/${configFile}`)
: tree.exists(joinPathFragments(`${projectRoot}/vite.config.ts`))
? joinPathFragments(`${projectRoot}/vite.config.ts`)
: tree.exists(joinPathFragments(`${projectRoot}/vite.config.js`))
? joinPathFragments(`${projectRoot}/vite.config.js`)
: undefined;
}

View File

@ -405,16 +405,13 @@ export function writeViteConfig(tree: Tree, options: Schema) {
host: 'localhost',
},`;
const projectsTsConfig = tree.exists('tsconfig.base.json')
? "'tsconfig.base.json'"
: '';
switch (options.uiFramework) {
case 'react':
viteConfigContent = `
${options.includeVitest ? '/// <reference types="vitest" />' : ''}
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
import viteTsConfigPaths from 'vite-tsconfig-paths';
${
options.includeLib
? `import dts from 'vite-plugin-dts';\nimport { join } from 'path';`
@ -426,9 +423,8 @@ ${options.includeVitest ? '/// <reference types="vitest" />' : ''}
plugins: [
${options.includeLib ? dtsPlugin : ''}
react(),
tsconfigPaths({
viteTsConfigPaths({
root: '${offsetFromRoot(projectConfig.root)}',
projects: [${projectsTsConfig}],
}),
],
${buildOption}
@ -440,7 +436,7 @@ ${options.includeVitest ? '/// <reference types="vitest" />' : ''}
viteConfigContent = `
${options.includeVitest ? '/// <reference types="vitest" />' : ''}
import { defineConfig } from 'vite';
import tsconfigPaths from 'vite-tsconfig-paths';
import viteTsConfigPaths from 'vite-tsconfig-paths';
${
options.includeLib
? `import dts from 'vite-plugin-dts';\nimport { join } from 'path';`
@ -451,9 +447,8 @@ ${options.includeVitest ? '/// <reference types="vitest" />' : ''}
${serverOption}
plugins: [
${options.includeLib ? dtsPlugin : ''}
tsconfigPaths({
viteTsConfigPaths({
root: '${offsetFromRoot(projectConfig.root)}',
projects: [${projectsTsConfig}],
}),
],
${buildOption}

View File

@ -4,6 +4,7 @@ import {
logger,
parseTargetString,
readTargetOptions,
Tree,
} from '@nrwl/devkit';
import { existsSync } from 'fs';
import { join, relative } from 'path';
@ -32,9 +33,9 @@ export async function getBuildAndSharedConfig(
root: projectRoot,
base: options.base,
configFile: normalizeConfigFilePath(
projectRoot,
options.configFile,
context.root,
projectRoot
context.root
),
plugins: [replaceFiles(options.fileReplacements)],
build: getViteBuildOptions(
@ -45,9 +46,9 @@ export async function getBuildAndSharedConfig(
}
export function normalizeConfigFilePath(
configFile: string,
workspaceRoot: string,
projectRoot: string
projectRoot: string,
configFile?: string,
workspaceRoot?: string
): string {
return configFile
? joinPathFragments(`${workspaceRoot}/${configFile}`)

View File

@ -0,0 +1,53 @@
{
"name": "my-test-react-vite-app",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"root": "apps/my-test-react-vite-app",
"sourceRoot": "apps/my-test-react-vite-app/src",
"projectType": "application",
"targets": {
"build": {
"executor": "@nrwl/vite:build",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"outputPath": "dist/apps/my-test-react-vite-app"
},
"configurations": {
"development": {},
"production": {}
}
},
"serve": {
"executor": "@nrwl/vite:dev-server",
"defaultConfiguration": "development",
"options": {
"buildTarget": "my-test-react-vite-app:build"
},
"configurations": {
"development": {
"buildTarget": "my-test-react-vite-app:build:development",
"hmr": true
},
"production": {
"buildTarget": "my-test-react-vite-app:build:production",
"hmr": false
}
}
},
"test": {
"executor": "@nrwl/vite:test",
"outputs": ["{projectRoot}/coverage"],
"options": {
"passWithNoTests": true
}
},
"lint": {
"executor": "@nrwl/linter:eslint",
"outputs": ["{options.outputFile}"],
"options": {
"lintFilePatterns": ["apps/my-test-react-vite-app/**/*.{ts,tsx,js,jsx}"]
}
}
},
"tags": []
}

View File

@ -1,7 +1,139 @@
import { Tree, writeJson } from '@nrwl/devkit';
import * as reactAppConfig from './test-files/react-project.config.json';
import * as reactViteConfig from './test-files/react-vite-project.config.json';
import * as webAppConfig from './test-files/web-project.config.json';
export function mockViteReactAppGenerator(tree: Tree): Tree {
const appName = 'my-test-react-vite-app';
tree.write(
`apps/${appName}/src/main.tsx`,
`import ReactDOM from 'react-dom';\n`
);
tree.write(
`apps/${appName}/tsconfig.json`,
`{
"compilerOptions": {
"jsx": "react-jsx",
"allowJs": false,
"esModuleInterop": false,
"allowSyntheticDefaultImports": true,
"strict": true,
"types": ["vite/client"]
},
"files": [],
"include": [],
"references": [
{
"path": "./tsconfig.app.json"
},
{
"path": "./tsconfig.spec.json"
}
],
"extends": "../../tsconfig.base.json"
}
`
);
tree.write(
`apps/${appName}/tsconfig.app.json`,
`{
"extends": "./tsconfig.json",
"compilerOptions": {
"outDir": "../../dist/out-tsc",
"types": ["node"]
},
"files": [
"../../node_modules/@nrwl/react/typings/cssmodule.d.ts",
"../../node_modules/@nrwl/react/typings/image.d.ts"
],
"exclude": [
"src/**/*.spec.ts",
"src/**/*.test.ts",
"src/**/*.spec.tsx",
"src/**/*.test.tsx",
"src/**/*.spec.js",
"src/**/*.test.js",
"src/**/*.spec.jsx",
"src/**/*.test.jsx"
],
"include": ["src/**/*.js", "src/**/*.jsx", "src/**/*.ts", "src/**/*.tsx"]
}
`
);
tree.write(
`apps/${appName}/index.html`,
`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Rv1</title>
<base href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="icon" type="image/x-icon" href="/favicon.ico" />
<link rel="stylesheet" href="/src/styles.css" />
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>`
);
tree.write(
`apps/${appName}/vite.config.ts`,
`/// <reference types="vitest" />
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
import tsconfigPaths from 'vite-tsconfig-paths';
export default defineConfig({
server: {
port: 4200,
host: 'localhost',
},
plugins: [
react(),
tsconfigPaths({
root: '../../',
projects: ['tsconfig.base.json'],
}),
],
test: {
globals: true,
cache: {
dir: '../../node_modules/.vitest',
},
environment: 'jsdom',
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
},
});
`
);
writeJson(tree, 'workspace.json', {
projects: {
'my-test-react-vite-app': {
...reactViteConfig,
root: `apps/${appName}`,
projectType: 'application',
},
},
});
writeJson(tree, `apps/${appName}/project.json`, {
...reactViteConfig,
root: `apps/${appName}`,
projectType: 'application',
});
return tree;
}
export function mockReactAppGenerator(tree: Tree): Tree {
const appName = 'my-test-react-app';
@ -84,20 +216,15 @@ export function mockReactAppGenerator(tree: Tree): Tree {
</html>`
);
writeJson(
tree,
'workspace.json',
{
projects: {
'my-test-react-app': {
...reactAppConfig,
root: `apps/${appName}`,
projectType: 'application',
},
writeJson(tree, 'workspace.json', {
projects: {
'my-test-react-app': {
...reactAppConfig,
root: `apps/${appName}`,
projectType: 'application',
},
}
);
},
});
writeJson(tree, `apps/${appName}/project.json`, {
...reactAppConfig,

View File

@ -6,7 +6,7 @@ export const vitestUiVersion = '^0.9.3';
export const vitePluginReactVersion = '^2.2.0';
export const vitePluginVueVersion = '^3.2.0';
export const vitePluginVueJsxVersion = '^2.1.1';
export const viteTsConfigPathsVersion = '^3.5.2';
export const viteTsConfigPathsVersion = '^4.0.1';
export const jsdomVersion = '~20.0.3';
export const vitePluginDtsVersion = '~1.7.1';