Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 739c427351 | |||
| f342baca5a | |||
| fd71c6e288 | |||
| d30413311b | |||
| 0761e4c7a9 | |||
| d15733d00e | |||
| eba45a9f5b | |||
| 68d9df74f6 | |||
| 1b4ac4b63e | |||
| 2959f7f033 | |||
| f997744b4d | |||
| 04a38649b3 | |||
| c351b34f62 | |||
| f111580f28 | |||
| bf9844ec72 | |||
| 6c86cb770c | |||
| c06edd9426 | |||
| 1c7406379b | |||
| f1de248ff7 | |||
| 5ba8d5aa12 | |||
| 18ff2dbcd4 | |||
| e9a59d60af | |||
| 908cf41d74 | |||
| 2f8ca66797 |
@@ -21,6 +21,13 @@
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"testEnvironment": {
|
||||
"type": "string",
|
||||
"enum": ["jsdom", "node", "none"],
|
||||
"description": "The test environment for jest. This controls which jest-environment-* package is installed",
|
||||
"default": "jsdom",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
||||
@@ -41,7 +41,7 @@
|
||||
},
|
||||
"testEnvironment": {
|
||||
"type": "string",
|
||||
"enum": ["jsdom", "node"],
|
||||
"enum": ["jsdom", "node", "none"],
|
||||
"description": "The test environment for jest.",
|
||||
"default": "jsdom",
|
||||
"x-priority": "important"
|
||||
|
||||
@@ -42,7 +42,7 @@ Sometimes broad configurations like `> 0.5%, not IE 11` can lead to surprising r
|
||||
|
||||
To see what browsers your configuration is supporting, run `npx browserslist` in the application's directory to get an output of browsers and versions to support.
|
||||
|
||||
```{% command="npx browserlist" %}
|
||||
```{% command="npx browserslist" %}
|
||||
and_chr 61
|
||||
chrome 83
|
||||
edge 83
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
uniq,
|
||||
updateFile,
|
||||
updateProjectConfig,
|
||||
removeFile,
|
||||
} from '../../utils';
|
||||
import { names } from '@nrwl/devkit';
|
||||
|
||||
@@ -19,154 +20,15 @@ describe('Angular Cypress Component Tests', () => {
|
||||
|
||||
beforeAll(async () => {
|
||||
projectName = newProject({ name: uniq('cy-ng') });
|
||||
runCLI(`generate @nrwl/angular:app ${appName} --no-interactive`);
|
||||
runCLI(
|
||||
`generate @nrwl/angular:component fancy-component --project=${appName} --no-interactive`
|
||||
);
|
||||
runCLI(`generate @nrwl/angular:lib ${usedInAppLibName} --no-interactive`);
|
||||
runCLI(
|
||||
`generate @nrwl/angular:component btn --project=${usedInAppLibName} --inlineTemplate --inlineStyle --export --no-interactive`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nrwl/angular:component btn-standalone --project=${usedInAppLibName} --inlineTemplate --inlineStyle --export --standalone --no-interactive`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${usedInAppLibName}/src/lib/btn/btn.component.ts`,
|
||||
`
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '${projectName}-btn',
|
||||
template: '<button class="text-green-500">{{text}}</button>',
|
||||
styles: []
|
||||
})
|
||||
export class BtnComponent {
|
||||
@Input() text = 'something';
|
||||
}
|
||||
`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${usedInAppLibName}/src/lib/btn-standalone/btn-standalone.component.ts`,
|
||||
`
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
@Component({
|
||||
selector: '${projectName}-btn-standalone',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
template: '<button class="text-green-500">standlone-{{text}}</button>',
|
||||
styles: [],
|
||||
})
|
||||
export class BtnStandaloneComponent {
|
||||
@Input() text = 'something';
|
||||
}
|
||||
`
|
||||
);
|
||||
// use lib in the app
|
||||
createFile(
|
||||
`apps/${appName}/src/app/app.component.html`,
|
||||
`
|
||||
<${projectName}-btn></${projectName}-btn>
|
||||
<${projectName}-btn-standalone></${projectName}-btn-standalone>
|
||||
<${projectName}-nx-welcome></${projectName}-nx-welcome>
|
||||
`
|
||||
);
|
||||
const btnModuleName = names(usedInAppLibName).className;
|
||||
updateFile(
|
||||
`apps/${appName}/src/app/app.component.scss`,
|
||||
`
|
||||
@use 'styleguide' as *;
|
||||
createApp(appName);
|
||||
|
||||
h1 {
|
||||
@include headline;
|
||||
}`
|
||||
);
|
||||
updateFile(
|
||||
`apps/${appName}/src/app/app.module.ts`,
|
||||
`
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import {${btnModuleName}Module} from "@${projectName}/${usedInAppLibName}";
|
||||
createLib(projectName, appName, usedInAppLibName);
|
||||
useLibInApp(projectName, appName, usedInAppLibName);
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { NxWelcomeComponent } from './nx-welcome.component';
|
||||
createBuildableLib(projectName, buildableLibName);
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent, NxWelcomeComponent],
|
||||
imports: [BrowserModule, ${btnModuleName}Module],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule {}
|
||||
`
|
||||
);
|
||||
|
||||
runCLI(
|
||||
`generate @nrwl/angular:lib ${buildableLibName} --buildable --no-interactive`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nrwl/angular:component input --project=${buildableLibName} --inlineTemplate --inlineStyle --export --no-interactive`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nrwl/angular:component input-standalone --project=${buildableLibName} --inlineTemplate --inlineStyle --export --standalone --no-interactive`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${buildableLibName}/src/lib/input/input.component.ts`,
|
||||
`
|
||||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '${projectName}-input',
|
||||
template: \`<label class="text-green-500">Email: <input class="border-blue-500" type="email" [readOnly]="readOnly"></label>\`,
|
||||
styles : []
|
||||
})
|
||||
export class InputComponent{
|
||||
@Input() readOnly = false;
|
||||
}
|
||||
`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${buildableLibName}/src/lib/input-standalone/input-standalone.component.ts`,
|
||||
`
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
@Component({
|
||||
selector: '${projectName}-input-standalone',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
template: \`<label class="text-green-500">Email: <input class="border-blue-500" type="email" [readOnly]="readOnly"></label>\`,
|
||||
styles : []
|
||||
})
|
||||
export class InputStandaloneComponent{
|
||||
@Input() readOnly = false;
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
// make sure assets from the workspace root work.
|
||||
createFile('libs/assets/data.json', JSON.stringify({ data: 'data' }));
|
||||
createFile(
|
||||
'assets/styles/styleguide.scss',
|
||||
`
|
||||
@mixin headline {
|
||||
font-weight: bold;
|
||||
color: darkkhaki;
|
||||
background: lightcoral;
|
||||
font-weight: 24px;
|
||||
}
|
||||
`
|
||||
);
|
||||
updateProjectConfig(appName, (config) => {
|
||||
config.targets['build'].options.stylePreprocessorOptions = {
|
||||
includePaths: ['assets/styles'],
|
||||
};
|
||||
config.targets['build'].options.assets.push({
|
||||
glob: '**/*',
|
||||
input: 'libs/assets',
|
||||
output: 'assets',
|
||||
});
|
||||
return config;
|
||||
});
|
||||
useWorkspaceAssetsInApp(appName);
|
||||
});
|
||||
|
||||
afterAll(() => cleanupProject());
|
||||
@@ -200,9 +62,226 @@ import {CommonModule} from '@angular/common';
|
||||
`generate @nrwl/angular:cypress-component-configuration --project=${buildableLibName} --generate-tests --no-interactive`
|
||||
);
|
||||
}).toThrow();
|
||||
createFile(
|
||||
|
||||
updateTestToAssertTailwindIsNotApplied(buildableLibName);
|
||||
|
||||
runCLI(
|
||||
`generate @nrwl/angular:cypress-component-configuration --project=${buildableLibName} --generate-tests --build-target=${appName}:build --no-interactive`
|
||||
);
|
||||
if (runCypressTests()) {
|
||||
expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain(
|
||||
'All specs passed!'
|
||||
);
|
||||
}
|
||||
// add tailwind
|
||||
runCLI(
|
||||
`generate @nrwl/angular:setup-tailwind --project=${buildableLibName}`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${buildableLibName}/src/lib/input/input.component.cy.ts`,
|
||||
`
|
||||
(content) => {
|
||||
// text-green-500 should now apply
|
||||
return content.replace('rgb(0, 0, 0)', 'rgb(34, 197, 94)');
|
||||
}
|
||||
);
|
||||
updateFile(
|
||||
`libs/${buildableLibName}/src/lib/input-standalone/input-standalone.component.cy.ts`,
|
||||
(content) => {
|
||||
// text-green-500 should now apply
|
||||
return content.replace('rgb(0, 0, 0)', 'rgb(34, 197, 94)');
|
||||
}
|
||||
);
|
||||
|
||||
if (runCypressTests()) {
|
||||
expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain(
|
||||
'All specs passed!'
|
||||
);
|
||||
checkFilesDoNotExist(`tmp/libs/${buildableLibName}/ct-styles.css`);
|
||||
}
|
||||
}, 300_000);
|
||||
|
||||
it('should test lib with implicit dep on buildTarget', () => {
|
||||
// creates graph like buildableLib -> lib -> app
|
||||
// updates the apps styles and they should apply to the buildableLib
|
||||
// even though app is not directly connected to buildableLib
|
||||
useBuildableLibInLib(projectName, buildableLibName, usedInAppLibName);
|
||||
|
||||
updateBuilableLibTestsToAssertAppStyles(appName, buildableLibName);
|
||||
|
||||
if (runCypressTests()) {
|
||||
expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain(
|
||||
'All specs passed!'
|
||||
);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
function createApp(appName: string) {
|
||||
runCLI(`generate @nrwl/angular:app ${appName} --no-interactive`);
|
||||
runCLI(
|
||||
`generate @nrwl/angular:component fancy-component --project=${appName} --no-interactive`
|
||||
);
|
||||
}
|
||||
|
||||
function createLib(projectName: string, appName: string, libName: string) {
|
||||
runCLI(`generate @nrwl/angular:lib ${libName} --no-interactive`);
|
||||
runCLI(
|
||||
`generate @nrwl/angular:component btn --project=${libName} --inlineTemplate --inlineStyle --export --no-interactive`
|
||||
);
|
||||
runCLI(
|
||||
`generate @nrwl/angular:component btn-standalone --project=${libName} --inlineTemplate --inlineStyle --export --standalone --no-interactive`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${libName}/src/lib/btn/btn.component.ts`,
|
||||
`
|
||||
import { Component, Input } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '${projectName}-btn',
|
||||
template: '<button class="text-green-500">{{text}}</button>',
|
||||
styles: []
|
||||
})
|
||||
export class BtnComponent {
|
||||
@Input() text = 'something';
|
||||
}
|
||||
`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${libName}/src/lib/btn-standalone/btn-standalone.component.ts`,
|
||||
`
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
@Component({
|
||||
selector: '${projectName}-btn-standalone',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
template: '<button class="text-green-500">standlone-{{text}}</button>',
|
||||
styles: [],
|
||||
})
|
||||
export class BtnStandaloneComponent {
|
||||
@Input() text = 'something';
|
||||
}
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
function createBuildableLib(projectName: string, libName: string) {
|
||||
// create lib
|
||||
runCLI(`generate @nrwl/angular:lib ${libName} --buildable --no-interactive`);
|
||||
// create cmp for lib
|
||||
runCLI(
|
||||
`generate @nrwl/angular:component input --project=${libName} --inlineTemplate --inlineStyle --export --no-interactive`
|
||||
);
|
||||
// create standlone cmp for lib
|
||||
runCLI(
|
||||
`generate @nrwl/angular:component input-standalone --project=${libName} --inlineTemplate --inlineStyle --export --standalone --no-interactive`
|
||||
);
|
||||
// update cmp implmentation to use tailwind clasasserting in tests
|
||||
updateFile(
|
||||
`libs/${libName}/src/lib/input/input.component.ts`,
|
||||
`
|
||||
import {Component, Input} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '${projectName}-input',
|
||||
template: \`<label class="text-green-500">Email: <input class="border-blue-500" type="email" [readOnly]="readOnly"></label>\`,
|
||||
styles : []
|
||||
})
|
||||
export class InputComponent{
|
||||
@Input() readOnly = false;
|
||||
}
|
||||
`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${libName}/src/lib/input-standalone/input-standalone.component.ts`,
|
||||
`
|
||||
import {Component, Input} from '@angular/core';
|
||||
import {CommonModule} from '@angular/common';
|
||||
@Component({
|
||||
selector: '${projectName}-input-standalone',
|
||||
standalone: true,
|
||||
imports: [CommonModule],
|
||||
template: \`<label class="text-green-500">Email: <input class="border-blue-500" type="email" [readOnly]="readOnly"></label>\`,
|
||||
styles : []
|
||||
})
|
||||
export class InputStandaloneComponent{
|
||||
@Input() readOnly = false;
|
||||
}
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
function useLibInApp(projectName: string, appName: string, libName: string) {
|
||||
createFile(
|
||||
`apps/${appName}/src/app/app.component.html`,
|
||||
`
|
||||
<${projectName}-btn></${projectName}-btn>
|
||||
<${projectName}-btn-standalone></${projectName}-btn-standalone>
|
||||
<${projectName}-nx-welcome></${projectName}-nx-welcome>
|
||||
`
|
||||
);
|
||||
const btnModuleName = names(libName).className;
|
||||
updateFile(
|
||||
`apps/${appName}/src/app/app.component.scss`,
|
||||
`
|
||||
@use 'styleguide' as *;
|
||||
|
||||
h1 {
|
||||
@include headline;
|
||||
}`
|
||||
);
|
||||
updateFile(
|
||||
`apps/${appName}/src/app/app.module.ts`,
|
||||
`
|
||||
import { NgModule } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import {${btnModuleName}Module} from "@${projectName}/${libName}";
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { NxWelcomeComponent } from './nx-welcome.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [AppComponent, NxWelcomeComponent],
|
||||
imports: [BrowserModule, ${btnModuleName}Module],
|
||||
providers: [],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule {}
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
function useWorkspaceAssetsInApp(appName: string) {
|
||||
// make sure assets from the workspace root work.
|
||||
createFile('libs/assets/data.json', JSON.stringify({ data: 'data' }));
|
||||
createFile(
|
||||
'assets/styles/styleguide.scss',
|
||||
`
|
||||
@mixin headline {
|
||||
font-weight: bold;
|
||||
color: darkkhaki;
|
||||
background: lightcoral;
|
||||
font-weight: 24px;
|
||||
}
|
||||
`
|
||||
);
|
||||
updateProjectConfig(appName, (config) => {
|
||||
config.targets['build'].options.stylePreprocessorOptions = {
|
||||
includePaths: ['assets/styles'],
|
||||
};
|
||||
config.targets['build'].options.assets.push({
|
||||
glob: '**/*',
|
||||
input: 'libs/assets',
|
||||
output: 'assets',
|
||||
});
|
||||
return config;
|
||||
});
|
||||
}
|
||||
|
||||
function updateTestToAssertTailwindIsNotApplied(libName: string) {
|
||||
createFile(
|
||||
`libs/${libName}/src/lib/input/input.component.cy.ts`,
|
||||
`
|
||||
import { MountConfig } from 'cypress/angular';
|
||||
import { InputComponent } from './input.component';
|
||||
|
||||
@@ -229,11 +308,11 @@ describe(InputComponent.name, () => {
|
||||
});
|
||||
});
|
||||
`
|
||||
);
|
||||
);
|
||||
|
||||
createFile(
|
||||
`libs/${buildableLibName}/src/lib/input-standalone/input-standalone.component.cy.ts`,
|
||||
`
|
||||
createFile(
|
||||
`libs/${libName}/src/lib/input-standalone/input-standalone.component.cy.ts`,
|
||||
`
|
||||
import { MountConfig } from 'cypress/angular';
|
||||
import { InputStandaloneComponent } from './input-standalone.component';
|
||||
|
||||
@@ -260,39 +339,50 @@ describe(InputStandaloneComponent.name, () => {
|
||||
});
|
||||
});
|
||||
`
|
||||
);
|
||||
);
|
||||
}
|
||||
function useBuildableLibInLib(
|
||||
projectName: string,
|
||||
buildableLibName: string,
|
||||
libName: string
|
||||
) {
|
||||
const buildLibNames = names(buildableLibName);
|
||||
// use the buildable lib in lib so now buildableLib has an indirect dep on app
|
||||
updateFile(
|
||||
`libs/${libName}/src/lib/btn-standalone/btn-standalone.component.ts`,
|
||||
`
|
||||
import { Component, Input } from '@angular/core';
|
||||
import { CommonModule } from '@angular/common';
|
||||
import { InputStandaloneComponent } from '@${projectName}/${buildLibNames.fileName}';
|
||||
@Component({
|
||||
selector: '${projectName}-btn-standalone',
|
||||
standalone: true,
|
||||
imports: [CommonModule, InputStandaloneComponent],
|
||||
template: '<button class="text-green-500">standlone-{{text}}</button>${projectName} <${projectName}-input-standalone></${projectName}-input-standalone>',
|
||||
styles: [],
|
||||
})
|
||||
export class BtnStandaloneComponent {
|
||||
@Input() text = 'something';
|
||||
}
|
||||
`
|
||||
);
|
||||
}
|
||||
|
||||
runCLI(
|
||||
`generate @nrwl/angular:cypress-component-configuration --project=${buildableLibName} --generate-tests --build-target=${appName}:build --no-interactive`
|
||||
);
|
||||
if (runCypressTests()) {
|
||||
expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain(
|
||||
'All specs passed!'
|
||||
);
|
||||
function updateBuilableLibTestsToAssertAppStyles(
|
||||
appName: string,
|
||||
buildableLibName: string
|
||||
) {
|
||||
updateFile(
|
||||
`apps/${appName}/src/styles.css`,
|
||||
`label {color: pink !important;}`
|
||||
);
|
||||
|
||||
removeFile(`libs/${buildableLibName}/src/lib/input/input.component.cy.ts`);
|
||||
updateFile(
|
||||
`libs/${buildableLibName}/src/lib/input-standalone/input-standalone.component.cy.ts`,
|
||||
(content) => {
|
||||
// app styles should now apply
|
||||
return content.replace('rgb(34, 197, 94)', 'rgb(255, 192, 203)');
|
||||
}
|
||||
|
||||
// add tailwind
|
||||
runCLI(
|
||||
`generate @nrwl/angular:setup-tailwind --project=${buildableLibName}`
|
||||
);
|
||||
updateFile(
|
||||
`libs/${buildableLibName}/src/lib/input/input.component.cy.ts`,
|
||||
(content) => {
|
||||
// text-green-500 should now apply
|
||||
return content.replace('rgb(0, 0, 0)', 'rgb(34, 197, 94)');
|
||||
}
|
||||
);
|
||||
updateFile(
|
||||
`libs/${buildableLibName}/src/lib/input-standalone/input-standalone.component.cy.ts`,
|
||||
(content) => {
|
||||
// text-green-500 should now apply
|
||||
return content.replace('rgb(0, 0, 0)', 'rgb(34, 197, 94)');
|
||||
}
|
||||
);
|
||||
|
||||
expect(runCLI(`component-test ${buildableLibName} --no-watch`)).toContain(
|
||||
'All specs passed!'
|
||||
);
|
||||
checkFilesDoNotExist(`tmp/libs/${buildableLibName}/ct-styles.css`);
|
||||
}, 300_000);
|
||||
});
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { satisfies } from 'semver';
|
||||
import { execSync } from 'child_process';
|
||||
import {
|
||||
checkFilesDoNotExist,
|
||||
checkFilesExist,
|
||||
@@ -21,7 +23,9 @@ describe('js e2e', () => {
|
||||
scope = newProject();
|
||||
});
|
||||
|
||||
afterEach(() => cleanupProject());
|
||||
afterEach(() => {
|
||||
cleanupProject();
|
||||
});
|
||||
|
||||
it('should create libs with js executors (--compiler=swc)', async () => {
|
||||
const lib = uniq('lib');
|
||||
@@ -103,7 +107,7 @@ describe('js e2e', () => {
|
||||
const swcHelpersFromDist = readJson(`dist/libs/${lib}/package.json`)
|
||||
.peerDependencies['@swc/helpers'];
|
||||
|
||||
expect(swcHelpersFromDist).toEqual(swcHelpersFromRoot);
|
||||
expect(satisfies(swcHelpersFromDist, swcHelpersFromRoot)).toBeTruthy();
|
||||
|
||||
updateJson(`libs/${lib}/.swcrc`, (json) => {
|
||||
json.jsc.externalHelpers = false;
|
||||
@@ -116,4 +120,50 @@ describe('js e2e', () => {
|
||||
'peerDependencies.@swc/helpers'
|
||||
);
|
||||
}, 240_000);
|
||||
|
||||
it('should handle swcrc path mappings', async () => {
|
||||
const lib = uniq('lib');
|
||||
runCLI(`generate @nrwl/js:lib ${lib} --compiler=swc --no-interactive`);
|
||||
|
||||
// add a dummy x.ts file for path mappings
|
||||
updateFile(
|
||||
`libs/${lib}/src/x.ts`,
|
||||
`
|
||||
export function x() {
|
||||
console.log('x');
|
||||
}
|
||||
`
|
||||
);
|
||||
|
||||
// update .swcrc to use path mappings
|
||||
updateJson(`libs/${lib}/.swcrc`, (json) => {
|
||||
json.jsc.paths = {
|
||||
'src/*': ['src/*'],
|
||||
};
|
||||
return json;
|
||||
});
|
||||
|
||||
// update lib.ts to use x
|
||||
updateFile(`libs/${lib}/src/lib/${lib}.ts`, () => {
|
||||
return `
|
||||
// @ts-ignore
|
||||
import { x } from 'src/x';
|
||||
|
||||
export function myLib() {
|
||||
console.log(x());
|
||||
}
|
||||
|
||||
myLib();
|
||||
`;
|
||||
});
|
||||
|
||||
// now run build
|
||||
runCLI(`build ${lib}`);
|
||||
|
||||
// invoke the lib with node
|
||||
const result = execSync(`node dist/libs/${lib}/src/lib/${lib}.js`, {
|
||||
cwd: tmpProjPath(),
|
||||
}).toString();
|
||||
expect(result).toContain('x');
|
||||
}, 240_000);
|
||||
});
|
||||
|
||||
@@ -137,8 +137,11 @@ describe('js e2e', () => {
|
||||
const rootPackageJson = readJson(`package.json`);
|
||||
|
||||
expect(
|
||||
readJson(`dist/libs/${lib}/package.json`).peerDependencies.tslib
|
||||
).toEqual(rootPackageJson.dependencies.tslib);
|
||||
satisfies(
|
||||
readJson(`dist/libs/${lib}/package.json`).peerDependencies.tslib,
|
||||
rootPackageJson.dependencies.tslib
|
||||
)
|
||||
).toBeTruthy();
|
||||
|
||||
updateJson(`libs/${lib}/tsconfig.json`, (json) => {
|
||||
json.compilerOptions = { ...json.compilerOptions, importHelpers: false };
|
||||
|
||||
+31
-15
@@ -27,6 +27,7 @@ import {
|
||||
import { exec, execSync } from 'child_process';
|
||||
import * as http from 'http';
|
||||
import { getLockFileName } from 'nx/src/lock-file/lock-file';
|
||||
import { satisfies } from 'semver';
|
||||
|
||||
function getData(port, path = '/api'): Promise<any> {
|
||||
return new Promise((resolve) => {
|
||||
@@ -263,21 +264,36 @@ describe('Build Node apps', () => {
|
||||
})
|
||||
);
|
||||
|
||||
expect(packageJson.dependencies['@nestjs/common']).toEqual(
|
||||
rootPackageJson.dependencies['@nestjs/common']
|
||||
);
|
||||
expect(packageJson.dependencies['@nestjs/core']).toEqual(
|
||||
rootPackageJson.dependencies['@nestjs/core']
|
||||
);
|
||||
expect(packageJson.dependencies['reflect-metadata']).toEqual(
|
||||
rootPackageJson.dependencies['reflect-metadata']
|
||||
);
|
||||
expect(packageJson.dependencies['rxjs']).toEqual(
|
||||
rootPackageJson.dependencies['rxjs']
|
||||
);
|
||||
expect(packageJson.dependencies['tslib']).toEqual(
|
||||
rootPackageJson.dependencies['tslib']
|
||||
);
|
||||
expect(
|
||||
satisfies(
|
||||
packageJson.dependencies['@nestjs/common'],
|
||||
rootPackageJson.dependencies['@nestjs/common']
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
satisfies(
|
||||
packageJson.dependencies['@nestjs/core'],
|
||||
rootPackageJson.dependencies['@nestjs/core']
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
satisfies(
|
||||
packageJson.dependencies['reflect-metadata'],
|
||||
rootPackageJson.dependencies['reflect-metadata']
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
satisfies(
|
||||
packageJson.dependencies['rxjs'],
|
||||
rootPackageJson.dependencies['rxjs']
|
||||
)
|
||||
).toBeTruthy();
|
||||
expect(
|
||||
satisfies(
|
||||
packageJson.dependencies['tslib'],
|
||||
rootPackageJson.dependencies['tslib']
|
||||
)
|
||||
).toBeTruthy();
|
||||
|
||||
checkFilesExist(
|
||||
`dist/apps/${nestapp}/${packageManagerLockFile[packageManager]}`
|
||||
|
||||
@@ -35,7 +35,7 @@ describe('Nx Commands', () => {
|
||||
|
||||
const s = runCLI('show projects').split('\n');
|
||||
|
||||
expect(s.length).toEqual(4);
|
||||
expect(s.length).toEqual(5);
|
||||
expect(s).toContain(app1);
|
||||
expect(s).toContain(app2);
|
||||
expect(s).toContain(`${app1}-e2e`);
|
||||
|
||||
@@ -73,14 +73,12 @@ describe('Nx Plugin', () => {
|
||||
// doesn't use the collection we are building
|
||||
// we should change it to point to the right collection using relative path
|
||||
// TODO: Re-enable this to work with pnpm
|
||||
xit(`should run the plugin's e2e tests`, async () => {
|
||||
if (isNotWindows()) {
|
||||
const plugin = uniq('plugin-name');
|
||||
runCLI(`generate @nrwl/nx-plugin:plugin ${plugin} --linter=eslint`);
|
||||
const e2eResults = runCLI(`e2e ${plugin}-e2e`);
|
||||
expect(e2eResults).toContain('Successfully ran target e2e');
|
||||
expect(await killPorts()).toBeTruthy();
|
||||
}
|
||||
it(`should run the plugin's e2e tests`, async () => {
|
||||
const plugin = uniq('plugin-name');
|
||||
runCLI(`generate @nrwl/nx-plugin:plugin ${plugin} --linter=eslint`);
|
||||
const e2eResults = runCLI(`e2e ${plugin}-e2e`);
|
||||
expect(e2eResults).toContain('Successfully ran target e2e');
|
||||
expect(await killPorts()).toBeTruthy();
|
||||
}, 250000);
|
||||
|
||||
it('should be able to generate a migration', async () => {
|
||||
|
||||
@@ -180,8 +180,6 @@ describe('Nx Affected and Graph Tests', () => {
|
||||
mylib = uniq('mylib');
|
||||
const nxJson: NxJsonConfiguration = readJson('nx.json');
|
||||
|
||||
delete nxJson.implicitDependencies;
|
||||
|
||||
updateFile('nx.json', JSON.stringify(nxJson));
|
||||
runCommand(`git init`);
|
||||
runCommand(`git config user.email "test@test.com"`);
|
||||
@@ -266,6 +264,24 @@ describe('Nx Affected and Graph Tests', () => {
|
||||
implicitDependencies: [],
|
||||
}));
|
||||
});
|
||||
|
||||
it('should handle file renames', () => {
|
||||
generateAll();
|
||||
|
||||
// Move file
|
||||
updateFile(
|
||||
`apps/${myapp2}/src/index.html`,
|
||||
readFile(`apps/${myapp}/src/index.html`)
|
||||
);
|
||||
removeFile(`apps/${myapp}/src/index.html`);
|
||||
|
||||
const affectedProjects = runCLI(
|
||||
'print-affected --uncommitted --select projects'
|
||||
).split(', ');
|
||||
|
||||
expect(affectedProjects).toContain(myapp);
|
||||
expect(affectedProjects).toContain(myapp2);
|
||||
});
|
||||
});
|
||||
|
||||
describe('print-affected', () => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {
|
||||
checkFilesDoNotExist,
|
||||
checkFilesExist,
|
||||
cleanupProject,
|
||||
getSize,
|
||||
killPorts,
|
||||
newProject,
|
||||
@@ -107,7 +108,7 @@ describe('Build React libraries and apps', () => {
|
||||
|
||||
afterEach(() => {
|
||||
killPorts();
|
||||
// cleanupProject();
|
||||
cleanupProject();
|
||||
});
|
||||
|
||||
describe('Buildable libraries', () => {
|
||||
|
||||
@@ -535,6 +535,10 @@ export function runCypressTests() {
|
||||
if (process.env.NX_E2E_RUN_CYPRESS === 'true') {
|
||||
ensureCypressInstallation();
|
||||
return true;
|
||||
} else {
|
||||
console.warn(
|
||||
'Not running Cypress because NX_E2E_RUN_CYPRESS is not set to true.'
|
||||
);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"packages": ["build/packages/*", "build/packages/nx/native-packages/*"],
|
||||
"version": "15.8.1",
|
||||
"version": "15.8.3",
|
||||
"granularPathspec": false,
|
||||
"command": {
|
||||
"publish": {
|
||||
|
||||
@@ -177,7 +177,7 @@
|
||||
"requires": {
|
||||
"@angular/core": ">=15.0.0"
|
||||
},
|
||||
"description": "Remove browserlist config as it's handled by build-angular",
|
||||
"description": "Remove browserslist config as it's handled by build-angular",
|
||||
"factory": "./src/migrations/update-15-2-0/remove-browserlist-config"
|
||||
},
|
||||
"update-typescript-target": {
|
||||
|
||||
@@ -22,7 +22,7 @@ import {
|
||||
workspaceRoot,
|
||||
} from '@nrwl/devkit';
|
||||
import { existsSync, lstatSync, mkdirSync, writeFileSync } from 'fs';
|
||||
import { dirname, join, relative } from 'path';
|
||||
import { dirname, join, relative, sep } from 'path';
|
||||
import type { BrowserBuilderSchema } from '../src/builders/webpack-browser/webpack-browser.impl';
|
||||
|
||||
/**
|
||||
@@ -168,13 +168,22 @@ function normalizeBuildTargetOptions(
|
||||
);
|
||||
const buildOptions = withSchemaDefaults(options);
|
||||
|
||||
// polyfill entries might be local files or files that are resolved from node_modules
|
||||
// like zone.js.
|
||||
// prevents error from webpack saying can't find <offset>/zone.js.
|
||||
const handlePolyfillPath = (polyfill: string) => {
|
||||
const maybeFullPath = join(workspaceRoot, polyfill.split('/').join(sep));
|
||||
if (existsSync(maybeFullPath)) {
|
||||
return joinPathFragments(offset, polyfill);
|
||||
}
|
||||
return polyfill;
|
||||
};
|
||||
// paths need to be unix paths for angular devkit
|
||||
buildOptions.polyfills =
|
||||
Array.isArray(buildOptions.polyfills) && buildOptions.polyfills.length > 0
|
||||
? (buildOptions.polyfills as string[]).map((p) =>
|
||||
joinPathFragments(offset, p)
|
||||
)
|
||||
: joinPathFragments(offset, buildOptions.polyfills as string);
|
||||
? (buildOptions.polyfills as string[]).map((p) => handlePolyfillPath(p))
|
||||
: handlePolyfillPath(buildOptions.polyfills as string);
|
||||
|
||||
buildOptions.main = joinPathFragments(offset, buildOptions.main);
|
||||
buildOptions.index =
|
||||
typeof buildOptions.index === 'string'
|
||||
@@ -197,6 +206,7 @@ function normalizeBuildTargetOptions(
|
||||
// then we don't want to have the assets/scripts/styles be included to
|
||||
// prevent inclusion of unintended stuff like tailwind
|
||||
if (
|
||||
buildContext.projectName === ctContext.projectName ||
|
||||
isCtProjectUsingBuildProject(
|
||||
ctContext.projectGraph,
|
||||
buildContext.projectName,
|
||||
|
||||
@@ -39,20 +39,36 @@ export function getTempTailwindPath(context: ExecutorContext) {
|
||||
}
|
||||
|
||||
/**
|
||||
* also returns true if the ct project and build project are the same.
|
||||
* i.e. component testing inside an app.
|
||||
*/
|
||||
* Checks if the childProjectName is a decendent of the parentProjectName
|
||||
* in the project graph
|
||||
**/
|
||||
export function isCtProjectUsingBuildProject(
|
||||
graph: ProjectGraph,
|
||||
parentProjectName: string,
|
||||
childProjectName: string
|
||||
) {
|
||||
return (
|
||||
parentProjectName === childProjectName ||
|
||||
graph.dependencies[parentProjectName].some(
|
||||
(p) => p.target === childProjectName
|
||||
)
|
||||
): boolean {
|
||||
const isProjectDirectDep = graph.dependencies[parentProjectName].some(
|
||||
(p) => p.target === childProjectName
|
||||
);
|
||||
if (isProjectDirectDep) {
|
||||
return true;
|
||||
}
|
||||
const maybeIntermediateProjects = graph.dependencies[
|
||||
parentProjectName
|
||||
].filter((p) => !graph.externalNodes[p.target]);
|
||||
|
||||
for (const maybeIntermediateProject of maybeIntermediateProjects) {
|
||||
if (
|
||||
isCtProjectUsingBuildProject(
|
||||
graph,
|
||||
maybeIntermediateProject.target,
|
||||
childProjectName
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
export function getProjectConfigByPath(
|
||||
|
||||
@@ -11,7 +11,8 @@ import { requireNx } from '../../nx';
|
||||
import { dirSync } from 'tmp';
|
||||
import { join } from 'path';
|
||||
|
||||
const { readJson, updateJson, getPackageManagerCommand } = requireNx();
|
||||
const { readJson, updateJson, getPackageManagerCommand, workspaceRoot } =
|
||||
requireNx();
|
||||
|
||||
const UNIDENTIFIED_VERSION = 'UNIDENTIFIED_VERSION';
|
||||
const NON_SEMVER_TAGS = {
|
||||
@@ -450,6 +451,7 @@ export function ensurePackage<T extends any = any>(
|
||||
stdio: [0, 1, 2],
|
||||
});
|
||||
|
||||
addToNodePath(join(workspaceRoot, 'node_modules'));
|
||||
addToNodePath(join(tempDir, 'node_modules'));
|
||||
|
||||
// Re-initialize the added paths into require
|
||||
@@ -473,6 +475,11 @@ function addToNodePath(dir: string) {
|
||||
? process.env.NODE_PATH.split(delimiter)
|
||||
: [];
|
||||
|
||||
// The path is already in the node path
|
||||
if (paths.includes(dir)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the tmp path
|
||||
paths.push(dir);
|
||||
|
||||
|
||||
@@ -202,6 +202,13 @@ export function getRelativeImportPath(exportedMember, filePath, basePath) {
|
||||
dirname(filePath),
|
||||
`${modulePath}.ts`
|
||||
);
|
||||
if (!existsSync(moduleFilePath)) {
|
||||
// might be a tsx file
|
||||
moduleFilePath = joinPathFragments(
|
||||
dirname(filePath),
|
||||
`${modulePath}.tsx`
|
||||
);
|
||||
}
|
||||
if (!existsSync(moduleFilePath)) {
|
||||
// might be a index.ts
|
||||
moduleFilePath = joinPathFragments(
|
||||
|
||||
@@ -131,6 +131,40 @@ export default {
|
||||
expect(packageJson.devDependencies['@types/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-node']).toBeDefined();
|
||||
expect(packageJson.devDependencies['jest-environment-jsdom']).toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-node']
|
||||
).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should add dependencies --testEnvironment=node', async () => {
|
||||
await jestInitGenerator(tree, { testEnvironment: 'node' });
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies.jest).toBeDefined();
|
||||
expect(packageJson.devDependencies['@nrwl/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['@types/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-node']).toBeDefined();
|
||||
expect(packageJson.devDependencies['jest-environment-node']).toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-jsdom']
|
||||
).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should add dependencies --testEnvironment=none', async () => {
|
||||
await jestInitGenerator(tree, { testEnvironment: 'none' });
|
||||
const packageJson = readJson(tree, 'package.json');
|
||||
expect(packageJson.devDependencies.jest).toBeDefined();
|
||||
expect(packageJson.devDependencies['@nrwl/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['@types/jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-jest']).toBeDefined();
|
||||
expect(packageJson.devDependencies['ts-node']).toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-jsdom']
|
||||
).not.toBeDefined();
|
||||
expect(
|
||||
packageJson.devDependencies['jest-environment-node']
|
||||
).not.toBeDefined();
|
||||
});
|
||||
|
||||
it('should make js jest files', async () => {
|
||||
|
||||
@@ -33,6 +33,7 @@ const schemaDefaults = {
|
||||
compiler: 'tsc',
|
||||
js: false,
|
||||
rootProject: false,
|
||||
testEnvironment: 'jsdom',
|
||||
} as const;
|
||||
|
||||
function generateGlobalConfig(tree: Tree, isJS: boolean) {
|
||||
@@ -146,7 +147,6 @@ function updateDependencies(tree: Tree, options: NormalizedSchema) {
|
||||
const devDeps = {
|
||||
'@nrwl/jest': nxVersion,
|
||||
jest: jestVersion,
|
||||
'jest-environment-jsdom': jestVersion,
|
||||
|
||||
// because the default jest-preset uses ts-jest,
|
||||
// jest will throw an error if it's not installed
|
||||
@@ -154,6 +154,10 @@ function updateDependencies(tree: Tree, options: NormalizedSchema) {
|
||||
'ts-jest': tsJestVersion,
|
||||
};
|
||||
|
||||
if (options.testEnvironment !== 'none') {
|
||||
devDeps[`jest-environment-${options.testEnvironment}`] = jestVersion;
|
||||
}
|
||||
|
||||
if (!options.js) {
|
||||
devDeps['ts-node'] = tsNodeVersion;
|
||||
devDeps['@types/jest'] = jestTypesVersion;
|
||||
|
||||
@@ -2,6 +2,7 @@ export interface JestInitSchema {
|
||||
compiler?: 'tsc' | 'babel' | 'swc';
|
||||
js?: boolean;
|
||||
skipPackageJson?: boolean;
|
||||
testEnvironment?: 'node' | 'jsdom' | 'none';
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
|
||||
@@ -18,6 +18,13 @@
|
||||
"description": "Do not add dependencies to `package.json`.",
|
||||
"x-priority": "internal"
|
||||
},
|
||||
"testEnvironment": {
|
||||
"type": "string",
|
||||
"enum": ["jsdom", "node", "none"],
|
||||
"description": "The test environment for jest. This controls which jest-environment-* package is installed",
|
||||
"default": "jsdom",
|
||||
"x-priority": "important"
|
||||
},
|
||||
"js": {
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
|
||||
@@ -18,15 +18,13 @@ const schemaDefaults = {
|
||||
skipSetupFile: false,
|
||||
skipSerializers: false,
|
||||
rootProject: false,
|
||||
testEnvironment: 'jsdom',
|
||||
} as const;
|
||||
|
||||
function normalizeOptions(options: JestProjectSchema) {
|
||||
if (!options.testEnvironment) {
|
||||
options.testEnvironment = 'jsdom';
|
||||
}
|
||||
if (options.testEnvironment === 'jsdom') {
|
||||
options.testEnvironment = '';
|
||||
}
|
||||
|
||||
if (!options.hasOwnProperty('supportTsx')) {
|
||||
options.supportTsx = false;
|
||||
|
||||
@@ -31,6 +31,11 @@ export function createFiles(tree: Tree, options: JestProjectSchema) {
|
||||
generateFiles(tree, join(__dirname, filesFolder), projectConfig.root, {
|
||||
tmpl: '',
|
||||
...options,
|
||||
// jsdom is the default
|
||||
testEnvironment:
|
||||
options.testEnvironment === 'none' || options.testEnvironment === 'jsdom'
|
||||
? ''
|
||||
: options.testEnvironment,
|
||||
transformer,
|
||||
transformerOptions,
|
||||
js: !!options.js,
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ export interface JestProjectSchema {
|
||||
skipSetupFile?: boolean;
|
||||
setupFile?: 'angular' | 'web-components' | 'none';
|
||||
skipSerializers?: boolean;
|
||||
testEnvironment?: 'node' | 'jsdom' | '';
|
||||
testEnvironment?: 'node' | 'jsdom' | 'none';
|
||||
/**
|
||||
* @deprecated use compiler: "babel" instead
|
||||
*/
|
||||
|
||||
@@ -40,7 +40,7 @@
|
||||
},
|
||||
"testEnvironment": {
|
||||
"type": "string",
|
||||
"enum": ["jsdom", "node"],
|
||||
"enum": ["jsdom", "node", "none"],
|
||||
"description": "The test environment for jest.",
|
||||
"default": "jsdom",
|
||||
"x-priority": "important"
|
||||
|
||||
@@ -42,7 +42,7 @@ module.exports = function (api: any, options: NxWebBabelPresetOptions = {}) {
|
||||
process.env.NODE_ENV === 'test'
|
||||
? { targets: { node: 'current' }, loose: true }
|
||||
: {
|
||||
// Allow importing core-js in entrypoint and use browserlist to select polyfills.
|
||||
// Allow importing core-js in entrypoint and use browserslist to select polyfills.
|
||||
useBuiltIns: options.useBuiltIns ?? 'entry',
|
||||
corejs: 3,
|
||||
// Do not transform modules to CJS
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ExecutorContext } from '@nrwl/devkit';
|
||||
import { ExecutorContext, readJsonFile, writeJsonFile } from '@nrwl/devkit';
|
||||
import {
|
||||
assetGlobsToFiles,
|
||||
FileInputOutput,
|
||||
@@ -24,6 +24,7 @@ import {
|
||||
import { compileSwc, compileSwcWatch } from '../../utils/swc/compile-swc';
|
||||
import { getSwcrcPath } from '../../utils/swc/get-swcrc-path';
|
||||
import { generateTmpSwcrc } from '../../utils/swc/inline';
|
||||
import type { Options } from '@swc/core';
|
||||
|
||||
export function normalizeOptions(
|
||||
options: SwcExecutorOptions,
|
||||
@@ -68,7 +69,21 @@ export function normalizeOptions(
|
||||
// default to current directory if projectRootParts is [].
|
||||
// Eg: when a project is at the root level, outside of layout dir
|
||||
const swcCwd = projectRootParts.join('/') || '.';
|
||||
const swcrcPath = getSwcrcPath(options, contextRoot, projectRoot);
|
||||
let swcrcPath = getSwcrcPath(options, contextRoot, projectRoot);
|
||||
|
||||
try {
|
||||
const swcrcContent = readJsonFile(swcrcPath) as Options;
|
||||
// if we have path mappings setup but baseUrl isn't specified, then we're proceeding with the following logic
|
||||
if (
|
||||
swcrcContent.jsc &&
|
||||
swcrcContent.jsc.paths &&
|
||||
!swcrcContent.jsc.baseUrl
|
||||
) {
|
||||
swcrcContent.jsc.baseUrl = `./${projectDir}`;
|
||||
swcrcPath = getSwcrcPath(options, contextRoot, projectRoot, true);
|
||||
writeJsonFile(swcrcPath, swcrcContent);
|
||||
}
|
||||
} catch (e) {}
|
||||
|
||||
const swcCliOptions = {
|
||||
srcPath: projectDir,
|
||||
@@ -190,7 +205,7 @@ export async function* swcExecutor(
|
||||
}
|
||||
|
||||
function removeTmpSwcrc(swcrcPath: string) {
|
||||
if (swcrcPath.startsWith('tmp/')) {
|
||||
if (swcrcPath.includes('tmp/') && swcrcPath.includes('.generated.swcrc')) {
|
||||
removeSync(dirname(swcrcPath));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,9 +4,14 @@ import { SwcExecutorOptions } from '../schema';
|
||||
export function getSwcrcPath(
|
||||
options: SwcExecutorOptions,
|
||||
contextRoot: string,
|
||||
projectRoot: string
|
||||
projectRoot: string,
|
||||
temp = false
|
||||
) {
|
||||
return options.swcrc
|
||||
? join(contextRoot, options.swcrc)
|
||||
: join(contextRoot, projectRoot, '.swcrc');
|
||||
let swcrcPath = options.swcrc ?? join(projectRoot, '.swcrc');
|
||||
|
||||
if (temp) {
|
||||
swcrcPath = join('tmp', swcrcPath.replace('.swcrc', '.generated.swcrc'));
|
||||
}
|
||||
|
||||
return join(contextRoot, swcrcPath);
|
||||
}
|
||||
|
||||
@@ -267,6 +267,7 @@ export async function addLintingToApplication(
|
||||
unitTestRunner: options.unitTestRunner,
|
||||
skipFormat: true,
|
||||
setParserOptionsProject: options.setParserOptionsProject,
|
||||
rootProject: options.rootProject,
|
||||
});
|
||||
|
||||
return lintTask;
|
||||
|
||||
@@ -47,7 +47,9 @@ export async function initGenerator(tree: Tree, schema: Schema) {
|
||||
})
|
||||
);
|
||||
if (options.unitTestRunner === 'jest') {
|
||||
tasks.push(await jestInitGenerator(tree, schema));
|
||||
tasks.push(
|
||||
await jestInitGenerator(tree, { ...schema, testEnvironment: 'node' })
|
||||
);
|
||||
}
|
||||
|
||||
tasks.push(updateDependencies(tree));
|
||||
|
||||
@@ -49,6 +49,12 @@ describe('lib', () => {
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(
|
||||
readJson(tree, 'package.json').devDependencies['jest-environment-jsdom']
|
||||
).not.toBeDefined();
|
||||
expect(
|
||||
readJson(tree, 'package.json').devDependencies['jest-environment-node']
|
||||
).toBeDefined();
|
||||
});
|
||||
|
||||
it('adds srcRootForCompilationRoot', async () => {
|
||||
|
||||
@@ -43,7 +43,7 @@ export function runNxCommandAsync(
|
||||
silenceError: false,
|
||||
}
|
||||
): Promise<{ stdout: string; stderr: string }> {
|
||||
if (fileExists('package.json')) {
|
||||
if (fileExists(tmpProjPath('package.json'))) {
|
||||
const pmc = getPackageManagerCommand();
|
||||
return runCommandAsync(`${pmc.exec} nx ${command}`, opts);
|
||||
} else if (process.platform === 'win32') {
|
||||
|
||||
@@ -21,7 +21,7 @@ export function runNxCommand(
|
||||
cwd: tmpProjPath(),
|
||||
env: { ...process.env, ...opts.env },
|
||||
};
|
||||
if (fileExists('package.json')) {
|
||||
if (fileExists(tmpProjPath('package.json'))) {
|
||||
const pmc = getPackageManagerCommand();
|
||||
return execSync(`${pmc.exec} nx ${command}`, execSyncOptions);
|
||||
} else if (process.platform === 'win32') {
|
||||
|
||||
@@ -62,6 +62,10 @@ if (
|
||||
|
||||
// this file is already in the local workspace
|
||||
if (localNx === resolveNx(null)) {
|
||||
if (localNx.includes('.nx') && !process.env.NX_WRAPPER_SET) {
|
||||
const nxWrapperPath = localNx.replace(/\.nx.*/, '.nx/') + 'nxw.js';
|
||||
require(nxWrapperPath);
|
||||
}
|
||||
initLocal(workspace);
|
||||
} else {
|
||||
// Nx is being run from globally installed CLI - hand off to the local
|
||||
|
||||
@@ -47,6 +47,12 @@
|
||||
"version": "15.0.12-beta.1",
|
||||
"description": "Set project names in project.json files",
|
||||
"implementation": "./src/migrations/update-15-1-0/set-project-names"
|
||||
},
|
||||
"15.8.2-update-nx-wrapper": {
|
||||
"cli": "nx",
|
||||
"version": "15.8.2-beta.0",
|
||||
"description": "Updates the nx wrapper in encapsulated repos.",
|
||||
"implementation": "./src/migrations/update-15-8-2/update-nxw"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import { createProjectGraphAsync } from '../project-graph/project-graph';
|
||||
import { filterAffected } from '../project-graph/affected/affected-project-graph';
|
||||
import { readNxJson } from '../config/configuration';
|
||||
import { ProjectGraph } from '../config/project-graph';
|
||||
import { chunkify } from '../utils/chunkify';
|
||||
|
||||
const PRETTIER_PATH = require.resolve('prettier/bin-prettier');
|
||||
|
||||
@@ -40,7 +41,7 @@ export async function format(
|
||||
);
|
||||
|
||||
// Chunkify the patterns array to prevent crashing the windows terminal
|
||||
const chunkList: string[][] = chunkify(patterns, 50);
|
||||
const chunkList: string[][] = chunkify(patterns);
|
||||
|
||||
switch (command) {
|
||||
case 'write':
|
||||
@@ -143,14 +144,6 @@ function getPatternsFromProjects(
|
||||
return getProjectRoots(projects, projectGraph);
|
||||
}
|
||||
|
||||
function chunkify(target: string[], size: number): string[][] {
|
||||
return target.reduce((current: string[][], value: string, index: number) => {
|
||||
if (index % size === 0) current.push([]);
|
||||
current[current.length - 1].push(value);
|
||||
return current;
|
||||
}, []);
|
||||
}
|
||||
|
||||
function write(patterns: string[]) {
|
||||
if (patterns.length > 0) {
|
||||
const [swcrcPatterns, regularPatterns] = patterns.reduce(
|
||||
|
||||
@@ -3,7 +3,10 @@ import { createProjectGraphAsync } from '../project-graph/project-graph';
|
||||
export async function show(args: { object: 'projects' }): Promise<void> {
|
||||
if (args.object == 'projects') {
|
||||
const graph = await createProjectGraphAsync();
|
||||
process.stdout.write(Object.keys(graph.nodes).join('\n'));
|
||||
const projects = Object.keys(graph.nodes).join('\n');
|
||||
if (projects.length) {
|
||||
console.log(projects);
|
||||
}
|
||||
} else {
|
||||
throw new Error(`Unrecognized option: ${args.object}`);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { spawn } from 'child_process';
|
||||
import { chunkify } from '../utils/chunkify';
|
||||
import { fileExists } from '../utils/fileutils';
|
||||
import { joinPathFragments } from '../utils/path';
|
||||
|
||||
@@ -12,26 +13,9 @@ export async function getGitHashForFiles(
|
||||
);
|
||||
|
||||
const res: Map<string, string> = new Map<string, string>();
|
||||
const promises: Promise<Map<string, string>>[] = [];
|
||||
if (filesToHash.length) {
|
||||
// On windows the max length is limited by the length of
|
||||
// the overall comand, rather than the number of individual
|
||||
// arguments. Since file paths are large and rather variable,
|
||||
// we use a smaller batchSize.
|
||||
const batchSize = process.platform === 'win32' ? 250 : 4000;
|
||||
for (
|
||||
let startIndex = 0;
|
||||
startIndex < filesToHash.length;
|
||||
startIndex += batchSize
|
||||
) {
|
||||
promises.push(
|
||||
getGitHashForBatch(
|
||||
filesToHash.slice(startIndex, startIndex + batchSize),
|
||||
path
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
const promises: Promise<Map<string, string>>[] = chunkify(filesToHash).map(
|
||||
(files) => getGitHashForBatch(files, path)
|
||||
);
|
||||
// Merge batch results into final result set
|
||||
const batchResults = await Promise.all(promises);
|
||||
for (const batch of batchResults) {
|
||||
|
||||
@@ -459,20 +459,12 @@ class TaskHasher {
|
||||
if (!this.filesetHashes[mapKey]) {
|
||||
this.filesetHashes[mapKey] = new Promise(async (res) => {
|
||||
const parts = [];
|
||||
if (fileset.indexOf('*') > -1) {
|
||||
this.projectGraph.allWorkspaceFiles
|
||||
.filter((f) => minimatch(f.file, withoutWorkspaceRoot))
|
||||
.forEach((f) => {
|
||||
parts.push(f.hash);
|
||||
});
|
||||
} else {
|
||||
const matchingFile = this.projectGraph.allWorkspaceFiles.find(
|
||||
(t) => t.file === withoutWorkspaceRoot
|
||||
);
|
||||
if (matchingFile) {
|
||||
parts.push(matchingFile.hash);
|
||||
}
|
||||
}
|
||||
this.projectGraph.allWorkspaceFiles
|
||||
.filter((f) => minimatch(f.file, withoutWorkspaceRoot))
|
||||
.forEach((f) => {
|
||||
parts.push(f.hash);
|
||||
});
|
||||
|
||||
const value = this.hashing.hashArray(parts);
|
||||
res({
|
||||
value,
|
||||
|
||||
@@ -141,7 +141,11 @@ function findVersion(
|
||||
) {
|
||||
return snapshot.resolution.slice(packageName.length + 1);
|
||||
}
|
||||
if (!isBerry && !satisfies(snapshot.version, versionRange)) {
|
||||
if (
|
||||
!isBerry &&
|
||||
snapshot.resolved &&
|
||||
!satisfies(snapshot.version, versionRange)
|
||||
) {
|
||||
return snapshot.resolved;
|
||||
}
|
||||
// otherwise it's a standard version
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
import {
|
||||
getNxWrapperContents,
|
||||
nxWrapperPath,
|
||||
} from 'nx/src/nx-init/encapsulated/add-nx-scripts';
|
||||
import { normalizePath } from '../../utils/path';
|
||||
import { Tree } from '../../generators/tree';
|
||||
|
||||
export default async function (tree: Tree) {
|
||||
const wrapperPath = normalizePath(nxWrapperPath());
|
||||
if (tree.exists(wrapperPath)) {
|
||||
tree.write(wrapperPath, getNxWrapperContents());
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ import {
|
||||
} from '../../generators/tree';
|
||||
import { writeJson } from '../../generators/utils/json';
|
||||
|
||||
const nxWrapperPath = (p: typeof import('path') = path) =>
|
||||
export const nxWrapperPath = (p: typeof import('path') = path) =>
|
||||
p.join('.nx', 'nxw.js');
|
||||
|
||||
const NODE_MISSING_ERR =
|
||||
@@ -36,7 +36,7 @@ export function generateEncapsulatedNxSetup(version?: string) {
|
||||
const host = new FsTree(process.cwd(), false);
|
||||
writeMinimalNxJson(host, version);
|
||||
updateGitIgnore(host);
|
||||
host.write(nxWrapperPath(), getNodeScriptContents());
|
||||
host.write(nxWrapperPath(), getNxWrapperContents());
|
||||
host.write('nx.bat', BATCH_SCRIPT_CONTENTS);
|
||||
host.write('nx', SHELL_SCRIPT_CONTENTS, {
|
||||
mode: FsConstants.S_IXUSR | FsConstants.S_IRUSR | FsConstants.S_IWUSR,
|
||||
@@ -75,7 +75,7 @@ export function updateGitIgnore(host: Tree) {
|
||||
);
|
||||
}
|
||||
|
||||
function getNodeScriptContents() {
|
||||
export function getNxWrapperContents() {
|
||||
// Read nxw.js, but remove any empty comments or comments that start with `//#: `
|
||||
// This removes the sourceMapUrl since it is invalid, as well as any internal comments.
|
||||
return readFileSync(path.join(__dirname, 'nxw.js'), 'utf-8').replace(
|
||||
|
||||
@@ -99,7 +99,8 @@ function ensureUpToDateInstallation() {
|
||||
}
|
||||
}
|
||||
|
||||
if (require.main === module) {
|
||||
if (require.main === module && !process.env.NX_WRAPPER_SET) {
|
||||
process.env.NX_WRAPPER_SET = 'true';
|
||||
ensureUpToDateInstallation();
|
||||
require('./installation/node_modules/nx/bin/nx');
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { existsSync } from 'fs';
|
||||
import { defaultHashing } from '../../../../hasher/hashing-impl';
|
||||
import { join } from 'path';
|
||||
|
||||
import { ProjectGraphBuilder } from '../../../../project-graph/project-graph-builder';
|
||||
@@ -16,13 +17,16 @@ export function buildNpmPackageNodes(builder: ProjectGraphBuilder) {
|
||||
...packageJson.devDependencies,
|
||||
};
|
||||
Object.keys(deps).forEach((d) => {
|
||||
builder.addExternalNode({
|
||||
type: 'npm',
|
||||
name: `npm:${d}`,
|
||||
data: {
|
||||
version: deps[d],
|
||||
packageName: d,
|
||||
},
|
||||
});
|
||||
if (!builder.graph.externalNodes[`npm:${d}`]) {
|
||||
builder.addExternalNode({
|
||||
type: 'npm',
|
||||
name: `npm:${d}`,
|
||||
data: {
|
||||
version: deps[d],
|
||||
packageName: d,
|
||||
hash: defaultHashing.hashArray([d, deps[d]]),
|
||||
},
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
+3
@@ -116,16 +116,19 @@ describe('explicit package json dependencies', () => {
|
||||
sourceProjectName: 'proj',
|
||||
targetProjectName: 'proj2',
|
||||
sourceProjectFile: 'libs/proj/package.json',
|
||||
type: 'static',
|
||||
},
|
||||
{
|
||||
sourceProjectFile: 'libs/proj/package.json',
|
||||
sourceProjectName: 'proj',
|
||||
targetProjectName: 'npm:external',
|
||||
type: 'static',
|
||||
},
|
||||
{
|
||||
sourceProjectName: 'proj',
|
||||
targetProjectName: 'proj3',
|
||||
sourceProjectFile: 'libs/proj/package.json',
|
||||
type: 'static',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
+7
-1
@@ -1,6 +1,10 @@
|
||||
import { defaultFileRead } from '../file-utils';
|
||||
import { join } from 'path';
|
||||
import { ProjectFileMap, ProjectGraph } from '../../config/project-graph';
|
||||
import {
|
||||
DependencyType,
|
||||
ProjectFileMap,
|
||||
ProjectGraph,
|
||||
} from '../../config/project-graph';
|
||||
import { parseJson } from '../../utils/json';
|
||||
import { getImportPath, joinPathFragments } from '../../utils/path';
|
||||
import { ProjectsConfigurations } from '../../config/workspace-json-project-json';
|
||||
@@ -88,12 +92,14 @@ function processPackageJson(
|
||||
sourceProjectName: sourceProject,
|
||||
targetProjectName: packageNameMap[d],
|
||||
sourceProjectFile: fileName,
|
||||
type: DependencyType.static,
|
||||
});
|
||||
} else if (graph.externalNodes[`npm:${d}`]) {
|
||||
collectedDeps.push({
|
||||
sourceProjectName: sourceProject,
|
||||
targetProjectName: `npm:${d}`,
|
||||
sourceProjectFile: fileName,
|
||||
type: DependencyType.static,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
@@ -67,6 +67,16 @@ export class ProjectGraphBuilder {
|
||||
* Adds a external node to the project graph
|
||||
*/
|
||||
addExternalNode(node: ProjectGraphExternalNode): void {
|
||||
// Check if project with the same name already exists
|
||||
if (this.graph.externalNodes[node.name]) {
|
||||
throw new Error(
|
||||
`Multiple projects are named "${node.name}". One has version "${
|
||||
node.data.version
|
||||
}" and the other has version "${
|
||||
this.graph.externalNodes[node.name].data.version
|
||||
}". Please resolve the conflicting package names.`
|
||||
);
|
||||
}
|
||||
this.graph.externalNodes[node.name] = node;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
import { chunkify } from './chunkify';
|
||||
|
||||
describe('chunkify', () => {
|
||||
it('should wrap chunks at passed in size', () => {
|
||||
const files = ['aa', 'bb', 'cc', 'dd', 'ee'];
|
||||
expect(chunkify(files, 4)).toHaveLength(5);
|
||||
expect(chunkify(files, 7)).toHaveLength(3);
|
||||
expect(chunkify(files, 16)).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('should contain all items from target', () => {
|
||||
const files = ['aa', 'bb', 'cc', 'dd', 'ee'];
|
||||
expect(chunkify(files, 7).flat()).toHaveLength(5);
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,41 @@
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
const TERMINAL_SIZE =
|
||||
process.platform === 'win32' ? 8192 : getUnixTerminalSize();
|
||||
|
||||
export function chunkify(
|
||||
target: string[],
|
||||
maxChunkLength: number = TERMINAL_SIZE - 500
|
||||
): string[][] {
|
||||
const chunks = [];
|
||||
let currentChunk = [];
|
||||
let currentChunkLength = 0;
|
||||
for (const file of target) {
|
||||
if (
|
||||
// Prevent empty chunk if first file path is longer than maxChunkLength
|
||||
currentChunk.length &&
|
||||
// +1 accounts for the space between file names
|
||||
currentChunkLength + file.length + 1 >= maxChunkLength
|
||||
) {
|
||||
chunks.push(currentChunk);
|
||||
currentChunk = [];
|
||||
currentChunkLength = 0;
|
||||
}
|
||||
currentChunk.push(file);
|
||||
currentChunkLength += file.length + 1;
|
||||
}
|
||||
chunks.push(currentChunk);
|
||||
return chunks;
|
||||
}
|
||||
|
||||
function getUnixTerminalSize() {
|
||||
try {
|
||||
const argMax = execSync('getconf ARG_MAX').toString().trim();
|
||||
return Number.parseInt(argMax);
|
||||
} catch {
|
||||
// This number varies by system, but 100k seems like a safe
|
||||
// number from some research...
|
||||
// https://stackoverflow.com/questions/19354870/bash-command-line-and-input-limit
|
||||
return 100000;
|
||||
}
|
||||
}
|
||||
@@ -222,7 +222,7 @@ export function parseFiles(options: NxArgs): { files: string[] } {
|
||||
}
|
||||
|
||||
function getUncommittedFiles(): string[] {
|
||||
return parseGitOutput(`git diff --name-only --relative HEAD .`);
|
||||
return parseGitOutput(`git diff --name-only --no-renames --relative HEAD .`);
|
||||
}
|
||||
|
||||
``;
|
||||
@@ -249,7 +249,7 @@ function getFilesUsingBaseAndHead(base: string, head: string): string[] {
|
||||
.trim();
|
||||
}
|
||||
return parseGitOutput(
|
||||
`git diff --name-only --relative "${mergeBase}" "${head}"`
|
||||
`git diff --name-only --no-renames --relative "${mergeBase}" "${head}"`
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -203,6 +203,7 @@ export function registerPluginTSTranspiler() {
|
||||
lib: ['es2021'],
|
||||
module: ts.ModuleKind.CommonJS,
|
||||
target: ts.ScriptTarget.ES2021,
|
||||
inlineSourceMap: true,
|
||||
esModuleInterop: true,
|
||||
skipLibCheck: true,
|
||||
experimentalDecorators: true,
|
||||
|
||||
@@ -44,6 +44,26 @@ describe('app', () => {
|
||||
expect(projects.get('my-app-e2e').root).toEqual('apps/my-app-e2e');
|
||||
});
|
||||
|
||||
it('should add vite types to tsconfigs', async () => {
|
||||
await applicationGenerator(appTree, {
|
||||
...schema,
|
||||
bundler: 'vite',
|
||||
unitTestRunner: 'vitest',
|
||||
});
|
||||
const tsconfigApp = readJson(appTree, 'apps/my-app/tsconfig.app.json');
|
||||
expect(tsconfigApp.compilerOptions.types).toEqual([
|
||||
'node',
|
||||
'vite/client',
|
||||
]);
|
||||
const tsconfigSpec = readJson(appTree, 'apps/my-app/tsconfig.spec.json');
|
||||
expect(tsconfigSpec.compilerOptions.types).toEqual([
|
||||
'vitest/globals',
|
||||
'vitest/importMeta',
|
||||
'vite/client',
|
||||
'node',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should not overwrite default project if already set', async () => {
|
||||
const nxJson = readNxJson(appTree);
|
||||
nxJson.defaultProject = 'some-awesome-project';
|
||||
|
||||
@@ -61,6 +61,26 @@ describe('lib', () => {
|
||||
});
|
||||
});
|
||||
|
||||
it('should add vite types to tsconfigs', async () => {
|
||||
await libraryGenerator(tree, {
|
||||
...defaultSchema,
|
||||
bundler: 'vite',
|
||||
unitTestRunner: 'vitest',
|
||||
});
|
||||
const tsconfigApp = readJson(tree, 'libs/my-lib/tsconfig.lib.json');
|
||||
expect(tsconfigApp.compilerOptions.types).toEqual([
|
||||
'node',
|
||||
'vite/client',
|
||||
]);
|
||||
const tsconfigSpec = readJson(tree, 'libs/my-lib/tsconfig.spec.json');
|
||||
expect(tsconfigSpec.compilerOptions.types).toEqual([
|
||||
'vitest/globals',
|
||||
'vitest/importMeta',
|
||||
'vite/client',
|
||||
'node',
|
||||
]);
|
||||
});
|
||||
|
||||
it('should update tags', async () => {
|
||||
await libraryGenerator(tree, { ...defaultSchema, tags: 'one,two' });
|
||||
const project = readProjectConfiguration(tree, 'my-lib');
|
||||
|
||||
@@ -51,9 +51,7 @@ export async function withModuleFederation(
|
||||
config.plugins.push(
|
||||
new ModuleFederationPlugin({
|
||||
name: options.name,
|
||||
library: {
|
||||
type: 'module',
|
||||
},
|
||||
library: options.library ?? { type: 'module' },
|
||||
filename: 'remoteEntry.js',
|
||||
exposes: options.exposes,
|
||||
remotes: mappedRemotes,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Tree } from 'nx/src/generators/tree';
|
||||
import * as shared from '@nrwl/js/src/utils/typescript/create-ts-config';
|
||||
import { writeJson } from 'nx/src/generators/utils/json';
|
||||
import { updateJson, writeJson } from 'nx/src/generators/utils/json';
|
||||
|
||||
export function createTsConfig(
|
||||
host: Tree,
|
||||
@@ -56,6 +56,21 @@ export function createTsConfig(
|
||||
}
|
||||
|
||||
writeJson(host, `${projectRoot}/tsconfig.json`, json);
|
||||
|
||||
const tsconfigProjectPath = `${projectRoot}/tsconfig.${type}.json`;
|
||||
if (options.bundler === 'vite' && host.exists(tsconfigProjectPath)) {
|
||||
updateJson(host, tsconfigProjectPath, (json) => {
|
||||
json.compilerOptions ??= {};
|
||||
|
||||
const types = new Set(json.compilerOptions.types ?? []);
|
||||
types.add('node');
|
||||
types.add('vite/client');
|
||||
|
||||
json.compilerOptions.types = Array.from(types);
|
||||
|
||||
return json;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function extractTsConfigBase(host: Tree) {
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"vite": "^4.0.1",
|
||||
"vitest": "^0.25.8"
|
||||
"vitest": ">=0.25.8 <1.0.0"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"extends": "./tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"types": ["vitest/globals", "node"]
|
||||
"types": ["vitest/globals", "vitest/importMeta", "vite/client", "node"]
|
||||
},
|
||||
"include": [
|
||||
"vite.config.ts",
|
||||
|
||||
@@ -93,6 +93,8 @@ describe('vitest generator', () => {
|
||||
"outDir": "../../dist/out-tsc",
|
||||
"types": Array [
|
||||
"vitest/globals",
|
||||
"vitest/importMeta",
|
||||
"vite/client",
|
||||
"node",
|
||||
],
|
||||
},
|
||||
|
||||
@@ -19,6 +19,7 @@ import { ViteDevServerExecutorOptions } from '../executors/dev-server/schema';
|
||||
import { VitePreviewServerExecutorOptions } from '../executors/preview-server/schema';
|
||||
import replaceFiles from '../../plugins/rollup-replace-files.plugin';
|
||||
import { ViteBuildExecutorOptions } from '../executors/build/schema';
|
||||
import * as path from 'path';
|
||||
|
||||
/**
|
||||
* Returns the path to the vite config file or undefined when not found.
|
||||
@@ -70,9 +71,14 @@ export function getViteSharedConfig(
|
||||
const projectRoot =
|
||||
context.projectsConfigurations.projects[context.projectName].root;
|
||||
|
||||
const root = path.relative(
|
||||
context.cwd,
|
||||
joinPathFragments(context.root, projectRoot)
|
||||
);
|
||||
|
||||
return {
|
||||
mode: options.mode,
|
||||
root: projectRoot,
|
||||
root,
|
||||
base: options.base,
|
||||
configFile: normalizeViteConfigFilePath(projectRoot, options.configFile),
|
||||
plugins: [replaceFiles(options.fileReplacements) as PluginOption],
|
||||
|
||||
@@ -513,6 +513,8 @@ describe('app', () => {
|
||||
).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"vitest/globals",
|
||||
"vitest/importMeta",
|
||||
"vite/client",
|
||||
"node",
|
||||
]
|
||||
`);
|
||||
|
||||
Reference in New Issue
Block a user