feat(js): update vue/node app and lib generators to support TS solutions (#29299)
<!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes # --------- Co-authored-by: Leosvel Pérez Espinosa <leosvel.perez.espinosa@gmail.com>
This commit is contained in:
parent
b6d41b617e
commit
a8de7df0e0
@ -33,14 +33,17 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-prompt": "Which unit test runner would you like to use?"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -37,13 +37,16 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-prompt": "Which unit test runner would you like to use?"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -31,13 +31,17 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-prompt": "Which unit test runner would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"description": "Add tags to the library (used for linting).",
|
"description": "Add tags to the library (used for linting).",
|
||||||
|
|||||||
@ -36,14 +36,26 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-priority": "important",
|
||||||
|
"x-prompt": "Which unit test runner would you like to use?"
|
||||||
|
},
|
||||||
|
"e2eTestRunner": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["jest", "none"],
|
||||||
|
"description": "Test runner to use for end-to-end tests",
|
||||||
|
"default": "none",
|
||||||
|
"x-priority": "important",
|
||||||
|
"x-prompt": "Which end-to-end test runner would you like to use?"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -109,12 +121,6 @@
|
|||||||
"hidden": true,
|
"hidden": true,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["jest", "none"],
|
|
||||||
"description": "Test runner to use for end to end (e2e) tests",
|
|
||||||
"default": "jest"
|
|
||||||
},
|
|
||||||
"docker": {
|
"docker": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Add a docker build target"
|
"description": "Add a docker build target"
|
||||||
|
|||||||
@ -36,14 +36,18 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-prompt": "Which unit test runner would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -69,7 +73,7 @@
|
|||||||
},
|
},
|
||||||
"buildable": {
|
"buildable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": true,
|
||||||
"description": "Generate a buildable library.",
|
"description": "Generate a buildable library.",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -22,24 +22,27 @@
|
|||||||
"pattern": "^[a-zA-Z][^:]*$",
|
"pattern": "^[a-zA-Z][^:]*$",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"linter": {
|
|
||||||
"description": "The tool to use for running lint checks.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["eslint"],
|
|
||||||
"default": "eslint"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "none"],
|
||||||
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "none"],
|
"enum": ["vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"x-prompt": "Which unit test runner would you like to use?",
|
"x-prompt": "Which unit test runner would you like to use?",
|
||||||
"default": "none"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -54,12 +54,6 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"linter": {
|
|
||||||
"description": "The tool to use for running lint checks.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["eslint", "none"],
|
|
||||||
"default": "eslint"
|
|
||||||
},
|
|
||||||
"routing": {
|
"routing": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Generate application with routes.",
|
"description": "Generate application with routes.",
|
||||||
@ -72,12 +66,21 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "none"],
|
||||||
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "none"],
|
"enum": ["vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"x-prompt": "Which unit test runner would you like to use?",
|
"x-prompt": "Which unit test runner would you like to use?",
|
||||||
"default": "vitest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -36,13 +36,17 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "none"],
|
"enum": ["vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"x-prompt": "What unit test runner should be used?"
|
"x-prompt": "What unit test runner should be used?",
|
||||||
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -772,7 +772,7 @@ describe('Linter', () => {
|
|||||||
const mylib = uniq('mylib');
|
const mylib = uniq('mylib');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app --name=${myapp} --linter eslint --directory="." --no-interactive`
|
`generate @nx/node:app --name=${myapp} --linter=eslint --directory="." --e2eTestRunner=jest --no-interactive`
|
||||||
);
|
);
|
||||||
runCLI('reset', { env: { CI: 'false' } });
|
runCLI('reset', { env: { CI: 'false' } });
|
||||||
verifySuccessfulStandaloneSetup(myapp);
|
verifySuccessfulStandaloneSetup(myapp);
|
||||||
|
|||||||
@ -141,7 +141,7 @@ describe('Jest', () => {
|
|||||||
it('should be able to test node lib with babel-jest', async () => {
|
it('should be able to test node lib with babel-jest', async () => {
|
||||||
const libName = uniq('babel-test-lib');
|
const libName = uniq('babel-test-lib');
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:lib libs/${libName} --buildable --importPath=@some-org/babel-test --publishable --babelJest`
|
`generate @nx/node:lib libs/${libName} --buildable --importPath=@some-org/babel-test --publishable --babelJest --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
const cliResults = await runCLIAsync(`test ${libName}`);
|
const cliResults = await runCLIAsync(`test ${libName}`);
|
||||||
|
|||||||
@ -24,7 +24,7 @@ describe('Node Applications + esbuild', () => {
|
|||||||
const app = uniq('nodeapp');
|
const app = uniq('nodeapp');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${app} --bundler=esbuild --no-interactive`
|
`generate @nx/node:app apps/${app} --bundler=esbuild --no-interactive --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
checkFilesDoNotExist(`apps/${app}/webpack.config.js`);
|
checkFilesDoNotExist(`apps/${app}/webpack.config.js`);
|
||||||
|
|||||||
@ -80,19 +80,23 @@ describe('Node Applications + webpack', () => {
|
|||||||
const nestApp = uniq('nest');
|
const nestApp = uniq('nest');
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
runCLI(`generate @nx/node:lib libs/${testLib1}`);
|
|
||||||
runCLI(`generate @nx/node:lib libs/${testLib2} --importPath=@acme/test2`);
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${expressApp} --framework=express --port=7000 --no-interactive`
|
`generate @nx/node:lib libs/${testLib1} --linter=eslint --unitTestRunner=jest --buildable=false`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${fastifyApp} --framework=fastify --port=7001 --no-interactive`
|
`generate @nx/node:lib libs/${testLib2} --importPath=@acme/test2 --linter=eslint --unitTestRunner=jest --buildable=false`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${koaApp} --framework=koa --port=7002 --no-interactive`
|
`generate @nx/node:app apps/${expressApp} --framework=express --port=7000 --no-interactive --linter=eslint --unitTestRunner=jest --e2eTestRunner=jest`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${nestApp} --framework=nest --port=7003 --bundler=webpack --no-interactive`
|
`generate @nx/node:app apps/${fastifyApp} --framework=fastify --port=7001 --no-interactive --linter=eslint --unitTestRunner=jest --e2eTestRunner=jest`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/node:app apps/${koaApp} --framework=koa --port=7002 --no-interactive --linter=eslint --unitTestRunner=jest --e2eTestRunner=jest`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/node:app apps/${nestApp} --framework=nest --port=7003 --bundler=webpack --no-interactive --linter=eslint --unitTestRunner=jest --e2eTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
addLibImport(expressApp, testLib1);
|
addLibImport(expressApp, testLib1);
|
||||||
@ -165,7 +169,7 @@ describe('Node Applications + webpack', () => {
|
|||||||
const expressApp = 'docker-express-app'; // needs to be consistent for the Dockerfile snapshot
|
const expressApp = 'docker-express-app'; // needs to be consistent for the Dockerfile snapshot
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${expressApp} --framework=express --docker --no-interactive`
|
`generate @nx/node:app apps/${expressApp} --framework=express --docker --no-interactive --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
checkFilesExist(`apps/${expressApp}/Dockerfile`);
|
checkFilesExist(`apps/${expressApp}/Dockerfile`);
|
||||||
@ -179,10 +183,10 @@ describe('Node Applications + webpack', () => {
|
|||||||
|
|
||||||
// Set ports to avoid conflicts with other tests that might run in parallel
|
// Set ports to avoid conflicts with other tests that might run in parallel
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${nodeApp1} --framework=none --no-interactive --port=4444`
|
`generate @nx/node:app apps/${nodeApp1} --framework=none --no-interactive --port=4444 --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${nodeApp2} --framework=none --no-interactive --port=4445`
|
`generate @nx/node:app apps/${nodeApp2} --framework=none --no-interactive --port=4445 --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
updateJson(join('apps', nodeApp1, 'project.json'), (config) => {
|
updateJson(join('apps', nodeApp1, 'project.json'), (config) => {
|
||||||
config.targets.serve.options.waitUntilTargets = [`${nodeApp2}:build`];
|
config.targets.serve.options.waitUntilTargets = [`${nodeApp2}:build`];
|
||||||
|
|||||||
170
e2e/node/src/node-ts-solution.test.ts
Normal file
170
e2e/node/src/node-ts-solution.test.ts
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
import {
|
||||||
|
checkFilesExist,
|
||||||
|
cleanupProject,
|
||||||
|
getPackageManagerCommand,
|
||||||
|
getSelectedPackageManager,
|
||||||
|
killPorts,
|
||||||
|
newProject,
|
||||||
|
promisifiedTreeKill,
|
||||||
|
runCLI,
|
||||||
|
runCommand,
|
||||||
|
runCommandUntil,
|
||||||
|
tmpProjPath,
|
||||||
|
uniq,
|
||||||
|
updateFile,
|
||||||
|
updateJson,
|
||||||
|
} from '@nx/e2e/utils';
|
||||||
|
import { execSync } from 'child_process';
|
||||||
|
import * as http from 'http';
|
||||||
|
|
||||||
|
let originalEnvPort;
|
||||||
|
|
||||||
|
describe('Node Applications', () => {
|
||||||
|
const pm = getSelectedPackageManager();
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
originalEnvPort = process.env.PORT;
|
||||||
|
newProject({
|
||||||
|
packages: ['@nx/node', '@nx/express', '@nx/nest', '@nx/webpack'],
|
||||||
|
preset: 'ts',
|
||||||
|
});
|
||||||
|
if (pm === 'pnpm') {
|
||||||
|
updateFile(
|
||||||
|
'pnpm-workspace.yaml',
|
||||||
|
`
|
||||||
|
packages:
|
||||||
|
- 'apps/**'
|
||||||
|
- 'packages/**'
|
||||||
|
`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
updateJson('package.json', (json) => {
|
||||||
|
json.workspaces = ['apps/**', 'packages/**'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => {
|
||||||
|
process.env.PORT = originalEnvPort;
|
||||||
|
cleanupProject();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to generate an empty application', async () => {
|
||||||
|
const nodeapp = uniq('nodeapp');
|
||||||
|
const port = getRandomPort();
|
||||||
|
process.env.PORT = `${port}`;
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/node:app apps/${nodeapp} --port=${port} --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`test ${nodeapp}`)).not.toThrow();
|
||||||
|
|
||||||
|
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
||||||
|
runCLI(`build ${nodeapp}`);
|
||||||
|
|
||||||
|
checkFilesExist(`dist/apps/${nodeapp}/main.js`);
|
||||||
|
const result = execSync(`node dist/apps/${nodeapp}/main.js`, {
|
||||||
|
cwd: tmpProjPath(),
|
||||||
|
}).toString();
|
||||||
|
expect(result).toContain('Hello World!');
|
||||||
|
await killPorts(port);
|
||||||
|
}, 300_000);
|
||||||
|
|
||||||
|
it('should be able to generate an express application', async () => {
|
||||||
|
const nodeapp = uniq('nodeapp');
|
||||||
|
const nodelib = uniq('nodelib');
|
||||||
|
const port = getRandomPort();
|
||||||
|
process.env.PORT = `${port}`;
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/express:app apps/${nodeapp} --port=${port} --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/node:lib packages/${nodelib} --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
|
// No tests are generated by default, add a stub one.
|
||||||
|
updateFile(
|
||||||
|
`apps/${nodeapp}/src/app/test.spec.ts`,
|
||||||
|
`
|
||||||
|
describe('test', () => {
|
||||||
|
it('should work', () => {
|
||||||
|
expect(true).toEqual(true);
|
||||||
|
})
|
||||||
|
})
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
updateFile(`apps/${nodeapp}/src/assets/file.txt`, `Test`);
|
||||||
|
updateFile(`apps/${nodeapp}/src/main.ts`, (content) => {
|
||||||
|
return `import { ${nodelib} } from '@proj/${nodelib}';\n${content}\nconsole.log(${nodelib}());`;
|
||||||
|
});
|
||||||
|
// pnpm does not link packages unless they are deps
|
||||||
|
// npm, yarn, and bun will link them in the root node_modules regardless
|
||||||
|
if (pm === 'pnpm') {
|
||||||
|
updateJson(`apps/${nodeapp}/package.json`, (json) => {
|
||||||
|
json.dependencies = {
|
||||||
|
[`@proj/${nodelib}`]: 'workspace:',
|
||||||
|
};
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
runCommand(getPackageManagerCommand().install);
|
||||||
|
}
|
||||||
|
runCLI(`sync`);
|
||||||
|
|
||||||
|
expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`test ${nodeapp}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`build ${nodeapp}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`lint ${nodelib}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`test ${nodelib}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`build ${nodelib}`)).not.toThrow();
|
||||||
|
|
||||||
|
const p = await runCommandUntil(
|
||||||
|
`serve ${nodeapp}`,
|
||||||
|
(output) => output.includes(`Listening at http://localhost:${port}`),
|
||||||
|
|
||||||
|
{
|
||||||
|
env: {
|
||||||
|
NX_DAEMON: 'true',
|
||||||
|
},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
let result = await getData(port);
|
||||||
|
expect(result.message).toMatch(`Welcome to ${nodeapp}!`);
|
||||||
|
|
||||||
|
result = await getData(port, '/assets/file.txt');
|
||||||
|
expect(result).toMatch(`Test`);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await promisifiedTreeKill(p.pid, 'SIGKILL');
|
||||||
|
expect(await killPorts(port)).toBeTruthy();
|
||||||
|
} catch (err) {
|
||||||
|
expect(err).toBeFalsy();
|
||||||
|
}
|
||||||
|
}, 300_000);
|
||||||
|
});
|
||||||
|
|
||||||
|
function getRandomPort() {
|
||||||
|
return Math.floor(1000 + Math.random() * 9000);
|
||||||
|
}
|
||||||
|
|
||||||
|
function getData(port, path = '/api'): Promise<any> {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
http.get(`http://localhost:${port}${path}`, (res) => {
|
||||||
|
expect(res.statusCode).toEqual(200);
|
||||||
|
let data = '';
|
||||||
|
res.on('data', (chunk) => {
|
||||||
|
data += chunk;
|
||||||
|
});
|
||||||
|
res.once('end', () => {
|
||||||
|
try {
|
||||||
|
resolve(JSON.parse(data));
|
||||||
|
} catch (e) {
|
||||||
|
resolve(data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -30,7 +30,7 @@ describe('Node Applications + webpack', () => {
|
|||||||
|
|
||||||
// This fails with Crystal enabled because `--optimization` is not a correct flag to pass to `webpack`.
|
// This fails with Crystal enabled because `--optimization` is not a correct flag to pass to `webpack`.
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${app} --bundler=webpack --no-interactive`,
|
`generate @nx/node:app apps/${app} --bundler=webpack --no-interactive --linter=eslint --unitTestRunner=jest`,
|
||||||
{
|
{
|
||||||
env: { NX_ADD_PLUGINS: 'false' },
|
env: { NX_ADD_PLUGINS: 'false' },
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,11 +72,11 @@ describe('Node Applications', () => {
|
|||||||
const port = getRandomPort();
|
const port = getRandomPort();
|
||||||
process.env.PORT = `${port}`;
|
process.env.PORT = `${port}`;
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${nodeapp} --port=${port} --linter=eslint`
|
`generate @nx/node:app apps/${nodeapp} --port=${port} --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nodeapp}`);
|
expect(() => runCLI(`lint ${nodeapp}`)).not.toThrow();
|
||||||
expect(lintResults).toContain('Successfully ran target lint');
|
expect(() => runCLI(`test ${nodeapp}`)).not.toThrow();
|
||||||
|
|
||||||
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
||||||
await runCLIAsync(`build ${nodeapp}`);
|
await runCLIAsync(`build ${nodeapp}`);
|
||||||
@ -92,7 +92,9 @@ describe('Node Applications', () => {
|
|||||||
// TODO(crystal, @ndcunningham): This does not work because NxWebpackPlugin({}) outputFilename does not work.
|
// TODO(crystal, @ndcunningham): This does not work because NxWebpackPlugin({}) outputFilename does not work.
|
||||||
xit('should be able to generate the correct outputFileName in options', async () => {
|
xit('should be able to generate the correct outputFileName in options', async () => {
|
||||||
const nodeapp = uniq('nodeapp');
|
const nodeapp = uniq('nodeapp');
|
||||||
runCLI(`generate @nx/node:app apps/${nodeapp} --linter=eslint`);
|
runCLI(
|
||||||
|
`generate @nx/node:app apps/${nodeapp} --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
updateJson(join('apps', nodeapp, 'project.json'), (config) => {
|
updateJson(join('apps', nodeapp, 'project.json'), (config) => {
|
||||||
config.targets.build.options.outputFileName = 'index.js';
|
config.targets.build.options.outputFileName = 'index.js';
|
||||||
@ -108,7 +110,7 @@ describe('Node Applications', () => {
|
|||||||
const port = getRandomPort();
|
const port = getRandomPort();
|
||||||
process.env.PORT = `${port}`;
|
process.env.PORT = `${port}`;
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${nodeapp} --port=${port} --linter=eslint --bundler=webpack`
|
`generate @nx/node:app apps/${nodeapp} --port=${port} --linter=eslint --bundler=webpack --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nodeapp}`);
|
const lintResults = runCLI(`lint ${nodeapp}`);
|
||||||
@ -190,7 +192,7 @@ module.exports = {
|
|||||||
const nodeapp = uniq('nodeapp');
|
const nodeapp = uniq('nodeapp');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${nodeapp} --linter=eslint --bundler=webpack --framework=none`
|
`generate @nx/node:app apps/${nodeapp} --linter=eslint --bundler=webpack --framework=none --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
updateFile('.env', `NX_FOOBAR="test foo bar"`);
|
updateFile('.env', `NX_FOOBAR="test foo bar"`);
|
||||||
@ -227,7 +229,9 @@ module.exports = {
|
|||||||
it("should exclude 'test' target from e2e project that uses jest", async () => {
|
it("should exclude 'test' target from e2e project that uses jest", async () => {
|
||||||
const appName = uniq('nodeapp');
|
const appName = uniq('nodeapp');
|
||||||
|
|
||||||
runCLI(`generate @nx/node:app ${appName} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/node:app ${appName} --no-interactive --unitTestRunner=jest --linter=eslint --e2eTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
const nxJson = JSON.parse(readFile('nx.json'));
|
const nxJson = JSON.parse(readFile('nx.json'));
|
||||||
expect(nxJson.plugins).toBeDefined();
|
expect(nxJson.plugins).toBeDefined();
|
||||||
@ -246,7 +250,7 @@ module.exports = {
|
|||||||
process.env.PORT = `${port}`;
|
process.env.PORT = `${port}`;
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/express:app apps/${nodeapp} --port=${port} --linter=eslint`
|
`generate @nx/express:app apps/${nodeapp} --port=${port} --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nodeapp}`);
|
const lintResults = runCLI(`lint ${nodeapp}`);
|
||||||
@ -296,7 +300,9 @@ module.exports = {
|
|||||||
it('should be able to generate a nest application', async () => {
|
it('should be able to generate a nest application', async () => {
|
||||||
const nestapp = uniq('nestapp');
|
const nestapp = uniq('nestapp');
|
||||||
const port = 3335;
|
const port = 3335;
|
||||||
runCLI(`generate @nx/nest:app apps/${nestapp} --linter=eslint`);
|
runCLI(
|
||||||
|
`generate @nx/nest:app apps/${nestapp} --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nestapp}`);
|
const lintResults = runCLI(`lint ${nestapp}`);
|
||||||
expect(lintResults).toContain('Successfully ran target lint');
|
expect(lintResults).toContain('Successfully ran target lint');
|
||||||
@ -344,7 +350,7 @@ module.exports = {
|
|||||||
const nestapp = 'node-nest-docker-test';
|
const nestapp = 'node-nest-docker-test';
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app ${nestapp} --bundler=webpack --framework=nest --docker`
|
`generate @nx/node:app ${nestapp} --bundler=webpack --framework=nest --docker --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
checkFilesExist(`${nestapp}/Dockerfile`);
|
checkFilesExist(`${nestapp}/Dockerfile`);
|
||||||
@ -359,7 +365,7 @@ module.exports = {
|
|||||||
const esmapp = uniq('esmapp');
|
const esmapp = uniq('esmapp');
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app ${esmapp} --linter=eslint --framework=none --bundler=webpack`
|
`generate @nx/node:app ${esmapp} --linter=eslint --framework=none --bundler=webpack --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
updateJson(`apps/${esmapp}/tsconfig.app.json`, (config) => {
|
updateJson(`apps/${esmapp}/tsconfig.app.json`, (config) => {
|
||||||
config.module = 'esnext';
|
config.module = 'esnext';
|
||||||
@ -424,7 +430,9 @@ describe('Build Node apps', () => {
|
|||||||
xit('should generate a package.json with the `--generatePackageJson` flag', async () => {
|
xit('should generate a package.json with the `--generatePackageJson` flag', async () => {
|
||||||
const packageManager = detectPackageManager(tmpProjPath());
|
const packageManager = detectPackageManager(tmpProjPath());
|
||||||
const nestapp = uniq('nestapp');
|
const nestapp = uniq('nestapp');
|
||||||
runCLI(`generate @nx/nest:app apps/${nestapp} --linter=eslint`);
|
runCLI(
|
||||||
|
`generate @nx/nest:app apps/${nestapp} --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
await runCLIAsync(`build ${nestapp} --generatePackageJson`);
|
await runCLIAsync(`build ${nestapp} --generatePackageJson`);
|
||||||
|
|
||||||
@ -485,7 +493,9 @@ describe('Build Node apps', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const nodeapp = uniq('nodeapp');
|
const nodeapp = uniq('nodeapp');
|
||||||
runCLI(`generate @nx/node:app ${nodeapp} --bundler=webpack`);
|
runCLI(
|
||||||
|
`generate @nx/node:app ${nodeapp} --bundler=webpack --unitTestRunner=jest --linter=eslint`
|
||||||
|
);
|
||||||
|
|
||||||
const jslib = uniq('jslib');
|
const jslib = uniq('jslib');
|
||||||
runCLI(`generate @nx/js:lib ${jslib} --bundler=tsc`);
|
runCLI(`generate @nx/js:lib ${jslib} --bundler=tsc`);
|
||||||
@ -529,7 +539,7 @@ ${jslib}();
|
|||||||
process.env.PORT = `${port}`;
|
process.env.PORT = `${port}`;
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:app apps/${appName} --port=${port} --no-interactive`
|
`generate @nx/node:app apps/${appName} --port=${port} --no-interactive --linter=eslint --unitTestRunner=jest`
|
||||||
);
|
);
|
||||||
|
|
||||||
// deleteOutputPath should default to true
|
// deleteOutputPath should default to true
|
||||||
@ -569,7 +579,9 @@ ${jslib}();
|
|||||||
const port = getRandomPort();
|
const port = getRandomPort();
|
||||||
process.env.PORT = `${port}`;
|
process.env.PORT = `${port}`;
|
||||||
|
|
||||||
runCLI(`generate @nx/node:app ${appName} --port=${port} --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/node:app ${appName} --port=${port} --no-interactive --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("apps/") and
|
// check files are generated without the layout directory ("apps/") and
|
||||||
// using the project name as the directory when no directory is provided
|
// using the project name as the directory when no directory is provided
|
||||||
@ -584,7 +596,9 @@ ${jslib}();
|
|||||||
`Successfully ran target test for project ${appName}`
|
`Successfully ran target test for project ${appName}`
|
||||||
);
|
);
|
||||||
|
|
||||||
runCLI(`generate @nx/node:lib ${libName} --buildable --no-interactive`);
|
runCLI(
|
||||||
|
`generate @nx/node:lib ${libName} --buildable --no-interactive --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
// check files are generated without the layout directory ("libs/") and
|
// check files are generated without the layout directory ("libs/") and
|
||||||
// using the project name as the directory when no directory is provided
|
// using the project name as the directory when no directory is provided
|
||||||
@ -605,7 +619,9 @@ ${jslib}();
|
|||||||
// TODO(crystal, @ndcunningham): What is the alternative here?
|
// TODO(crystal, @ndcunningham): What is the alternative here?
|
||||||
xit('should have plugin output if specified in `tsPlugins`', async () => {
|
xit('should have plugin output if specified in `tsPlugins`', async () => {
|
||||||
const nestapp = uniq('nestapp');
|
const nestapp = uniq('nestapp');
|
||||||
runCLI(`generate @nx/nest:app ${nestapp} --linter=eslint`);
|
runCLI(
|
||||||
|
`generate @nx/nest:app ${nestapp} --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
packageInstall('@nestjs/swagger', undefined, '^7.0.0');
|
packageInstall('@nestjs/swagger', undefined, '^7.0.0');
|
||||||
|
|
||||||
@ -659,7 +675,9 @@ ${jslib}();
|
|||||||
describe('nest libraries', function () {
|
describe('nest libraries', function () {
|
||||||
it('should be able to generate a nest library', async () => {
|
it('should be able to generate a nest library', async () => {
|
||||||
const nestlib = uniq('nestlib');
|
const nestlib = uniq('nestlib');
|
||||||
runCLI(`generate @nx/nest:lib libs/${nestlib}`);
|
runCLI(
|
||||||
|
`generate @nx/nest:lib libs/${nestlib} --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nestlib}`);
|
const lintResults = runCLI(`lint ${nestlib}`);
|
||||||
expect(lintResults).toContain('Successfully ran target lint');
|
expect(lintResults).toContain('Successfully ran target lint');
|
||||||
@ -673,7 +691,9 @@ ${jslib}();
|
|||||||
it('should be able to generate a nest library w/ service', async () => {
|
it('should be able to generate a nest library w/ service', async () => {
|
||||||
const nestlib = uniq('nestlib');
|
const nestlib = uniq('nestlib');
|
||||||
|
|
||||||
runCLI(`generate @nx/nest:lib ${nestlib} --service`);
|
runCLI(
|
||||||
|
`generate @nx/nest:lib ${nestlib} --service --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nestlib}`);
|
const lintResults = runCLI(`lint ${nestlib}`);
|
||||||
expect(lintResults).toContain('Successfully ran target lint');
|
expect(lintResults).toContain('Successfully ran target lint');
|
||||||
@ -687,7 +707,9 @@ ${jslib}();
|
|||||||
it('should be able to generate a nest library w/ controller', async () => {
|
it('should be able to generate a nest library w/ controller', async () => {
|
||||||
const nestlib = uniq('nestlib');
|
const nestlib = uniq('nestlib');
|
||||||
|
|
||||||
runCLI(`generate @nx/nest:lib ${nestlib} --controller`);
|
runCLI(
|
||||||
|
`generate @nx/nest:lib ${nestlib} --controller --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nestlib}`);
|
const lintResults = runCLI(`lint ${nestlib}`);
|
||||||
expect(lintResults).toContain('Successfully ran target lint');
|
expect(lintResults).toContain('Successfully ran target lint');
|
||||||
@ -701,7 +723,9 @@ ${jslib}();
|
|||||||
it('should be able to generate a nest library w/ controller and service', async () => {
|
it('should be able to generate a nest library w/ controller and service', async () => {
|
||||||
const nestlib = uniq('nestlib');
|
const nestlib = uniq('nestlib');
|
||||||
|
|
||||||
runCLI(`generate @nx/nest:lib ${nestlib} --controller --service`);
|
runCLI(
|
||||||
|
`generate @nx/nest:lib ${nestlib} --controller --service --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nestlib}`);
|
const lintResults = runCLI(`lint ${nestlib}`);
|
||||||
expect(lintResults).toContain('Successfully ran target lint');
|
expect(lintResults).toContain('Successfully ran target lint');
|
||||||
@ -714,7 +738,9 @@ ${jslib}();
|
|||||||
|
|
||||||
it('should have plugin output if specified in `transformers`', async () => {
|
it('should have plugin output if specified in `transformers`', async () => {
|
||||||
const nestlib = uniq('nestlib');
|
const nestlib = uniq('nestlib');
|
||||||
runCLI(`generate @nx/nest:lib libs/${nestlib} --buildable`);
|
runCLI(
|
||||||
|
`generate @nx/nest:lib libs/${nestlib} --buildable --linter=eslint --unitTestRunner=jest`
|
||||||
|
);
|
||||||
|
|
||||||
packageInstall('@nestjs/swagger', undefined, '^7.0.0');
|
packageInstall('@nestjs/swagger', undefined, '^7.0.0');
|
||||||
|
|
||||||
@ -758,9 +784,5 @@ exports.FooModel = FooModel;
|
|||||||
`
|
`
|
||||||
);
|
);
|
||||||
}, 300000);
|
}, 300000);
|
||||||
|
|
||||||
it('should run default jest tests', async () => {
|
|
||||||
await expectJestTestsToPass('@nx/node:lib');
|
|
||||||
}, 100000);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -16,7 +16,7 @@ describe('Nuxt Plugin', () => {
|
|||||||
packages: ['@nx/nuxt'],
|
packages: ['@nx/nuxt'],
|
||||||
});
|
});
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/nuxt:app ${app} --unitTestRunner=vitest --e2eTestRunner=cypress`
|
`generate @nx/nuxt:app ${app} --unitTestRunner=vitest --e2eTestRunner=cypress --linter=eslint`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/nuxt:component ${app}/src/components/one/one --name=one --unitTestRunner=vitest`
|
`generate @nx/nuxt:component ${app}/src/components/one/one --name=one --unitTestRunner=vitest`
|
||||||
|
|||||||
@ -589,7 +589,7 @@ describe('Nx Running Tests', () => {
|
|||||||
`generate @nx/js:lib ${libC} --bundler=tsc --defaults --tags=ui-b,shared --directory=libs/${libC}`
|
`generate @nx/js:lib ${libC} --bundler=tsc --defaults --tags=ui-b,shared --directory=libs/${libC}`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nx/node:lib ${libD} --defaults --tags=api --directory=libs/${libD}`
|
`generate @nx/node:lib ${libD} --defaults --tags=api --directory=libs/${libD} --buildable=false`
|
||||||
);
|
);
|
||||||
|
|
||||||
// libA depends on libC
|
// libA depends on libC
|
||||||
|
|||||||
@ -76,10 +76,12 @@ export function newProject({
|
|||||||
name = uniq('proj'),
|
name = uniq('proj'),
|
||||||
packageManager = getSelectedPackageManager(),
|
packageManager = getSelectedPackageManager(),
|
||||||
packages,
|
packages,
|
||||||
|
preset = 'apps',
|
||||||
}: {
|
}: {
|
||||||
name?: string;
|
name?: string;
|
||||||
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
|
packageManager?: 'npm' | 'yarn' | 'pnpm' | 'bun';
|
||||||
readonly packages?: Array<NxPackage>;
|
readonly packages?: Array<NxPackage>;
|
||||||
|
preset?: string;
|
||||||
} = {}): string {
|
} = {}): string {
|
||||||
const newProjectStart = performance.mark('new-project:start');
|
const newProjectStart = performance.mark('new-project:start');
|
||||||
try {
|
try {
|
||||||
@ -93,7 +95,7 @@ export function newProject({
|
|||||||
'create-nx-workspace:start'
|
'create-nx-workspace:start'
|
||||||
);
|
);
|
||||||
runCreateWorkspace(projScope, {
|
runCreateWorkspace(projScope, {
|
||||||
preset: 'apps',
|
preset,
|
||||||
packageManager,
|
packageManager,
|
||||||
});
|
});
|
||||||
const createNxWorkspaceEnd = performance.mark('create-nx-workspace:end');
|
const createNxWorkspaceEnd = performance.mark('create-nx-workspace:end');
|
||||||
|
|||||||
75
e2e/vue/src/vue-ts-solution.test.ts
Normal file
75
e2e/vue/src/vue-ts-solution.test.ts
Normal file
@ -0,0 +1,75 @@
|
|||||||
|
import {
|
||||||
|
cleanupProject,
|
||||||
|
getSelectedPackageManager,
|
||||||
|
newProject,
|
||||||
|
runCLI,
|
||||||
|
uniq,
|
||||||
|
updateFile,
|
||||||
|
updateJson,
|
||||||
|
} from '@nx/e2e/utils';
|
||||||
|
|
||||||
|
describe('Vue Plugin', () => {
|
||||||
|
let proj: string;
|
||||||
|
|
||||||
|
const pm = getSelectedPackageManager();
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
proj = newProject({
|
||||||
|
packages: ['@nx/vue'],
|
||||||
|
preset: 'ts',
|
||||||
|
});
|
||||||
|
if (pm === 'pnpm') {
|
||||||
|
updateFile(
|
||||||
|
'pnpm-workspace.yaml',
|
||||||
|
`
|
||||||
|
packages:
|
||||||
|
- 'apps/**'
|
||||||
|
- 'packages/**'
|
||||||
|
`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
updateJson('package.json', (json) => {
|
||||||
|
json.workspaces = ['apps/**', 'packages/**'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
afterAll(() => cleanupProject());
|
||||||
|
|
||||||
|
it('should serve application in dev mode', async () => {
|
||||||
|
const app = uniq('app');
|
||||||
|
const lib = uniq('lib');
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/vue:app apps/${app} --unitTestRunner=vitest --e2eTestRunner=playwright --linter=eslint`
|
||||||
|
);
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/vue:lib packages/${lib} --bundler=vite --unitTestRunner=vitest --linter=eslint`
|
||||||
|
);
|
||||||
|
|
||||||
|
// app and lib generators don't have specs by default, add some stubs
|
||||||
|
updateFile(
|
||||||
|
`apps/${app}/src/foo.spec.ts`,
|
||||||
|
`
|
||||||
|
test('it should run', () => {
|
||||||
|
expect(true).toBeTruthy();
|
||||||
|
});
|
||||||
|
`
|
||||||
|
);
|
||||||
|
updateFile(
|
||||||
|
`packages/${lib}/src/foo.spec.ts`,
|
||||||
|
`
|
||||||
|
test('it should run', () => {
|
||||||
|
expect(true).toBeTruthy();
|
||||||
|
});
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(() => runCLI(`lint ${app}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`test ${app}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`build ${app}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`lint ${lib}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`test ${lib}`)).not.toThrow();
|
||||||
|
expect(() => runCLI(`build ${lib}`)).not.toThrow();
|
||||||
|
}, 300_000);
|
||||||
|
});
|
||||||
@ -32,6 +32,9 @@ import { printSocialInformation } from '../src/utils/social-information';
|
|||||||
|
|
||||||
interface BaseArguments extends CreateWorkspaceOptions {
|
interface BaseArguments extends CreateWorkspaceOptions {
|
||||||
preset: Preset;
|
preset: Preset;
|
||||||
|
linter?: 'none' | 'eslint';
|
||||||
|
formatter?: 'none' | 'prettier';
|
||||||
|
workspaces?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NoneArguments extends BaseArguments {
|
interface NoneArguments extends BaseArguments {
|
||||||
@ -39,7 +42,6 @@ interface NoneArguments extends BaseArguments {
|
|||||||
workspaceType?: 'package-based' | 'integrated' | 'standalone';
|
workspaceType?: 'package-based' | 'integrated' | 'standalone';
|
||||||
js?: boolean;
|
js?: boolean;
|
||||||
appName?: string | undefined;
|
appName?: string | undefined;
|
||||||
formatter?: 'none' | 'prettier';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ReactArguments extends BaseArguments {
|
interface ReactArguments extends BaseArguments {
|
||||||
@ -52,9 +54,6 @@ interface ReactArguments extends BaseArguments {
|
|||||||
nextAppDir: boolean;
|
nextAppDir: boolean;
|
||||||
nextSrcDir: boolean;
|
nextSrcDir: boolean;
|
||||||
e2eTestRunner: 'none' | 'cypress' | 'playwright';
|
e2eTestRunner: 'none' | 'cypress' | 'playwright';
|
||||||
linter?: 'none' | 'eslint';
|
|
||||||
formatter?: 'none' | 'prettier';
|
|
||||||
workspaces?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface AngularArguments extends BaseArguments {
|
interface AngularArguments extends BaseArguments {
|
||||||
@ -730,6 +729,10 @@ async function determineVueOptions(
|
|||||||
let style: undefined | string = undefined;
|
let style: undefined | string = undefined;
|
||||||
let appName: string;
|
let appName: string;
|
||||||
let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined;
|
let e2eTestRunner: undefined | 'none' | 'cypress' | 'playwright' = undefined;
|
||||||
|
let linter: undefined | 'none' | 'eslint';
|
||||||
|
let formatter: undefined | 'none' | 'prettier';
|
||||||
|
|
||||||
|
const workspaces = parsedArgs.workspaces ?? false;
|
||||||
|
|
||||||
if (parsedArgs.preset && parsedArgs.preset !== Preset.Vue) {
|
if (parsedArgs.preset && parsedArgs.preset !== Preset.Vue) {
|
||||||
preset = parsedArgs.preset;
|
preset = parsedArgs.preset;
|
||||||
@ -741,7 +744,9 @@ async function determineVueOptions(
|
|||||||
} else {
|
} else {
|
||||||
const framework = await determineVueFramework(parsedArgs);
|
const framework = await determineVueFramework(parsedArgs);
|
||||||
|
|
||||||
const workspaceType = await determineStandaloneOrMonorepo();
|
const workspaceType = workspaces
|
||||||
|
? 'monorepo'
|
||||||
|
: await determineStandaloneOrMonorepo();
|
||||||
if (workspaceType === 'standalone') {
|
if (workspaceType === 'standalone') {
|
||||||
appName = parsedArgs.appName ?? parsedArgs.name;
|
appName = parsedArgs.appName ?? parsedArgs.name;
|
||||||
} else {
|
} else {
|
||||||
@ -798,7 +803,23 @@ async function determineVueOptions(
|
|||||||
style = reply.style;
|
style = reply.style;
|
||||||
}
|
}
|
||||||
|
|
||||||
return { preset, style, appName, e2eTestRunner };
|
if (workspaces) {
|
||||||
|
linter = await determineLinterOptions(parsedArgs);
|
||||||
|
formatter = await determineFormatterOptions(parsedArgs);
|
||||||
|
} else {
|
||||||
|
linter = 'eslint';
|
||||||
|
formatter = 'prettier';
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
preset,
|
||||||
|
style,
|
||||||
|
appName,
|
||||||
|
e2eTestRunner,
|
||||||
|
linter,
|
||||||
|
formatter,
|
||||||
|
workspaces,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async function determineAngularOptions(
|
async function determineAngularOptions(
|
||||||
@ -967,6 +988,10 @@ async function determineNodeOptions(
|
|||||||
let appName: string;
|
let appName: string;
|
||||||
let framework: 'express' | 'fastify' | 'koa' | 'nest' | 'none';
|
let framework: 'express' | 'fastify' | 'koa' | 'nest' | 'none';
|
||||||
let docker: boolean;
|
let docker: boolean;
|
||||||
|
let linter: undefined | 'none' | 'eslint';
|
||||||
|
let formatter: undefined | 'none' | 'prettier';
|
||||||
|
|
||||||
|
const workspaces = parsedArgs.workspaces ?? false;
|
||||||
|
|
||||||
if (parsedArgs.preset) {
|
if (parsedArgs.preset) {
|
||||||
preset = parsedArgs.preset;
|
preset = parsedArgs.preset;
|
||||||
@ -989,7 +1014,9 @@ async function determineNodeOptions(
|
|||||||
} else {
|
} else {
|
||||||
framework = await determineNodeFramework(parsedArgs);
|
framework = await determineNodeFramework(parsedArgs);
|
||||||
|
|
||||||
const workspaceType = await determineStandaloneOrMonorepo();
|
const workspaceType = workspaces
|
||||||
|
? 'monorepo'
|
||||||
|
: await determineStandaloneOrMonorepo();
|
||||||
if (workspaceType === 'standalone') {
|
if (workspaceType === 'standalone') {
|
||||||
preset = Preset.NodeStandalone;
|
preset = Preset.NodeStandalone;
|
||||||
appName = parsedArgs.name;
|
appName = parsedArgs.name;
|
||||||
@ -1024,11 +1051,22 @@ async function determineNodeOptions(
|
|||||||
docker = reply.docker === 'Yes';
|
docker = reply.docker === 'Yes';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (workspaces) {
|
||||||
|
linter = await determineLinterOptions(parsedArgs);
|
||||||
|
formatter = await determineFormatterOptions(parsedArgs);
|
||||||
|
} else {
|
||||||
|
linter = 'eslint';
|
||||||
|
formatter = 'prettier';
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
preset,
|
preset,
|
||||||
appName,
|
appName,
|
||||||
framework,
|
framework,
|
||||||
docker,
|
docker,
|
||||||
|
linter,
|
||||||
|
formatter,
|
||||||
|
workspaces,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -32,7 +32,6 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@nx/devkit": "file:../devkit",
|
"@nx/devkit": "file:../devkit",
|
||||||
"@nx/js": "file:../js",
|
|
||||||
"@nx/node": "file:../node",
|
"@nx/node": "file:../node",
|
||||||
"tslib": "^2.3.0"
|
"tslib": "^2.3.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { readJson, Tree } from '@nx/devkit';
|
import { readJson, Tree, updateJson, writeJson } from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { applicationGenerator } from './application';
|
import { applicationGenerator } from './application';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
@ -134,4 +134,178 @@ describe('app', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
appTree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(appTree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(appTree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(appTree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await applicationGenerator(appTree, {
|
||||||
|
directory: 'myapp',
|
||||||
|
} as Schema);
|
||||||
|
|
||||||
|
expect(readJson(appTree, 'tsconfig.json').references)
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./myapp-e2e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./myapp",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(appTree, 'myapp/package.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"name": "@proj/myapp",
|
||||||
|
"nx": {
|
||||||
|
"name": "myapp",
|
||||||
|
"projectType": "application",
|
||||||
|
"sourceRoot": "myapp/src",
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"configurations": {
|
||||||
|
"development": {},
|
||||||
|
"production": {},
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "production",
|
||||||
|
"executor": "@nx/webpack:webpack",
|
||||||
|
"options": {
|
||||||
|
"assets": [
|
||||||
|
"myapp/src/assets",
|
||||||
|
],
|
||||||
|
"compiler": "tsc",
|
||||||
|
"main": "myapp/src/main.ts",
|
||||||
|
"outputPath": "dist/myapp",
|
||||||
|
"target": "node",
|
||||||
|
"tsConfig": "myapp/tsconfig.app.json",
|
||||||
|
"webpackConfig": "myapp/webpack.config.js",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{options.outputPath}",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"lint": {
|
||||||
|
"executor": "@nx/eslint:lint",
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"configurations": {
|
||||||
|
"development": {
|
||||||
|
"buildTarget": "myapp:build:development",
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"buildTarget": "myapp:build:production",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"executor": "@nx/js:node",
|
||||||
|
"options": {
|
||||||
|
"buildTarget": "myapp:build",
|
||||||
|
"runBuildTargetDependencies": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"options": {
|
||||||
|
"passWithNoTests": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.1",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(appTree, 'myapp/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(appTree, 'myapp/tsconfig.app.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"outDir": "out-tsc/myapp",
|
||||||
|
"rootDir": "src",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
"express",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"eslint.config.js",
|
||||||
|
"eslint.config.cjs",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(appTree, 'myapp/tsconfig.spec.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"outDir": "./out-tsc/jest",
|
||||||
|
"types": [
|
||||||
|
"jest",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,7 +11,6 @@ import {
|
|||||||
determineProjectNameAndRootOptions,
|
determineProjectNameAndRootOptions,
|
||||||
ensureProjectName,
|
ensureProjectName,
|
||||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
|
import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
|
||||||
import { tslibVersion } from '@nx/node/src/utils/versions';
|
import { tslibVersion } from '@nx/node/src/utils/versions';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
@ -75,8 +74,6 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'express', 'application');
|
|
||||||
|
|
||||||
const options = await normalizeOptions(tree, schema);
|
const options = await normalizeOptions(tree, schema);
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|||||||
@ -33,14 +33,17 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-prompt": "Which unit test runner would you like to use?"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import {
|
|||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { expressVersion, nxVersion } from '../../utils/versions';
|
import { expressVersion, nxVersion } from '../../utils/versions';
|
||||||
import type { Schema } from './schema';
|
import type { Schema } from './schema';
|
||||||
|
|
||||||
@ -29,8 +28,6 @@ function updateDependencies(tree: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function initGenerator(tree: Tree, schema: Schema) {
|
export async function initGenerator(tree: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'express', 'init');
|
|
||||||
|
|
||||||
let installTask: GeneratorCallback = () => {};
|
let installTask: GeneratorCallback = () => {};
|
||||||
if (!schema.skipPackageJson) {
|
if (!schema.skipPackageJson) {
|
||||||
installTask = updateDependencies(tree, schema);
|
installTask = updateDependencies(tree, schema);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { Tree } from '@nx/devkit';
|
import { readJson, updateJson, writeJson, type Tree } from '@nx/devkit';
|
||||||
import * as devkit from '@nx/devkit';
|
import * as devkit from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { applicationGenerator } from './application';
|
import { applicationGenerator } from './application';
|
||||||
@ -66,6 +66,11 @@ describe('application generator', () => {
|
|||||||
"runBuildTargetDependencies": false,
|
"runBuildTargetDependencies": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"test": {
|
||||||
|
"options": {
|
||||||
|
"passWithNoTests": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
@ -162,4 +167,169 @@ describe('application generator', () => {
|
|||||||
expect(projectConfigurations.get(`${appDirectory}-e2e`)).toBeUndefined();
|
expect(projectConfigurations.get(`${appDirectory}-e2e`)).toBeUndefined();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await applicationGenerator(tree, {
|
||||||
|
directory: 'myapp',
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
addPlugin: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./myapp-e2e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./myapp",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/package.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"name": "@proj/myapp",
|
||||||
|
"nx": {
|
||||||
|
"name": "myapp",
|
||||||
|
"projectType": "application",
|
||||||
|
"sourceRoot": "myapp/src",
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"configurations": {
|
||||||
|
"development": {
|
||||||
|
"args": [
|
||||||
|
"node-env=development",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"executor": "nx:run-commands",
|
||||||
|
"options": {
|
||||||
|
"args": [
|
||||||
|
"node-env=production",
|
||||||
|
],
|
||||||
|
"command": "webpack-cli build",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"serve": {
|
||||||
|
"configurations": {
|
||||||
|
"development": {
|
||||||
|
"buildTarget": "myapp:build:development",
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"buildTarget": "myapp:build:production",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"executor": "@nx/js:node",
|
||||||
|
"options": {
|
||||||
|
"buildTarget": "myapp:build",
|
||||||
|
"runBuildTargetDependencies": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"options": {
|
||||||
|
"passWithNoTests": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.1",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.app.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"emitDecoratorMetadata": true,
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"outDir": "out-tsc/myapp",
|
||||||
|
"rootDir": "src",
|
||||||
|
"target": "es2021",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"eslint.config.js",
|
||||||
|
"eslint.config.cjs",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.spec.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"outDir": "./out-tsc/jest",
|
||||||
|
"types": [
|
||||||
|
"jest",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||||
import { formatFiles, runTasksInSerial } from '@nx/devkit';
|
import { formatFiles, runTasksInSerial } from '@nx/devkit';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
|
import { applicationGenerator as nodeApplicationGenerator } from '@nx/node';
|
||||||
|
|
||||||
import { initGenerator } from '../init/init';
|
import { initGenerator } from '../init/init';
|
||||||
@ -27,8 +26,6 @@ export async function applicationGeneratorInternal(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
rawOptions: ApplicationGeneratorOptions
|
rawOptions: ApplicationGeneratorOptions
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'nest', 'application');
|
|
||||||
|
|
||||||
const options = await normalizeOptions(tree, rawOptions);
|
const options = await normalizeOptions(tree, rawOptions);
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|||||||
@ -15,6 +15,7 @@ export interface ApplicationGeneratorOptions {
|
|||||||
rootProject?: boolean;
|
rootProject?: boolean;
|
||||||
strict?: boolean;
|
strict?: boolean;
|
||||||
addPlugin?: boolean;
|
addPlugin?: boolean;
|
||||||
|
useTsSolution?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NormalizedOptions extends ApplicationGeneratorOptions {
|
interface NormalizedOptions extends ApplicationGeneratorOptions {
|
||||||
|
|||||||
@ -37,13 +37,16 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-prompt": "Which unit test runner would you like to use?"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||||
import { formatFiles } from '@nx/devkit';
|
import { formatFiles } from '@nx/devkit';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
|
|
||||||
import { addDependencies } from './lib';
|
import { addDependencies } from './lib';
|
||||||
import type { InitGeneratorOptions } from './schema';
|
import type { InitGeneratorOptions } from './schema';
|
||||||
@ -9,8 +8,6 @@ export async function initGenerator(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
options: InitGeneratorOptions
|
options: InitGeneratorOptions
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'nest', 'init');
|
|
||||||
|
|
||||||
let installPackagesTask: GeneratorCallback = () => {};
|
let installPackagesTask: GeneratorCallback = () => {};
|
||||||
if (!options.skipPackageJson) {
|
if (!options.skipPackageJson) {
|
||||||
installPackagesTask = addDependencies(tree, options);
|
installPackagesTask = addDependencies(tree, options);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import type { Tree } from '@nx/devkit';
|
import type { Tree } from '@nx/devkit';
|
||||||
import * as devkit from '@nx/devkit';
|
import * as devkit from '@nx/devkit';
|
||||||
import { readJson, readProjectConfiguration } from '@nx/devkit';
|
import { readJson, readProjectConfiguration, writeJson } from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { libraryGenerator } from './library';
|
import { libraryGenerator } from './library';
|
||||||
|
|
||||||
@ -345,4 +345,114 @@ describe('lib', () => {
|
|||||||
).toBeTruthy();
|
).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
devkit.updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'mylib',
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./mylib",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'mylib/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.lib.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'mylib/tsconfig.lib.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"emitDeclarationOnly": false,
|
||||||
|
"forceConsistentCasingInFileNames": true,
|
||||||
|
"importHelpers": true,
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"noFallthroughCasesInSwitch": true,
|
||||||
|
"noImplicitAny": true,
|
||||||
|
"noImplicitOverride": true,
|
||||||
|
"noImplicitReturns": true,
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src",
|
||||||
|
"strict": true,
|
||||||
|
"strictBindCallApply": true,
|
||||||
|
"strictNullChecks": true,
|
||||||
|
"target": "es6",
|
||||||
|
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
],
|
||||||
|
"references": [],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'mylib/tsconfig.spec.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/jest",
|
||||||
|
"types": [
|
||||||
|
"jest",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.lib.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
import type { GeneratorCallback, Tree } from '@nx/devkit';
|
||||||
import { formatFiles, runTasksInSerial } from '@nx/devkit';
|
import { formatFiles, runTasksInSerial } from '@nx/devkit';
|
||||||
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import {
|
import {
|
||||||
addExportsToBarrelFile,
|
addExportsToBarrelFile,
|
||||||
addProject,
|
addProject,
|
||||||
@ -30,8 +29,6 @@ export async function libraryGeneratorInternal(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
rawOptions: LibraryGeneratorOptions
|
rawOptions: LibraryGeneratorOptions
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'nest', 'library');
|
|
||||||
|
|
||||||
const options = await normalizeOptions(tree, rawOptions);
|
const options = await normalizeOptions(tree, rawOptions);
|
||||||
await jsLibraryGenerator(tree, toJsLibraryGeneratorOptions(options));
|
await jsLibraryGenerator(tree, toJsLibraryGeneratorOptions(options));
|
||||||
const initTask = await initGenerator(tree, rawOptions);
|
const initTask = await initGenerator(tree, rawOptions);
|
||||||
|
|||||||
@ -31,13 +31,17 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-prompt": "Which unit test runner would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"description": "Add tags to the library (used for linting).",
|
"description": "Add tags to the library (used for linting).",
|
||||||
|
|||||||
@ -6,6 +6,8 @@ import {
|
|||||||
readJson,
|
readJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
|
|
||||||
@ -59,6 +61,11 @@ describe('app', () => {
|
|||||||
"runBuildTargetDependencies": false,
|
"runBuildTargetDependencies": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"test": {
|
||||||
|
"options": {
|
||||||
|
"passWithNoTests": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
@ -266,6 +273,11 @@ describe('app', () => {
|
|||||||
"runBuildTargetDependencies": false,
|
"runBuildTargetDependencies": false,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
"test": {
|
||||||
|
"options": {
|
||||||
|
"passWithNoTests": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
`);
|
`);
|
||||||
@ -548,4 +560,152 @@ describe('app', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await applicationGenerator(tree, {
|
||||||
|
directory: 'myapp',
|
||||||
|
bundler: 'webpack',
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
addPlugin: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./myapp-e2e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./myapp",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/package.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"name": "@proj/myapp",
|
||||||
|
"nx": {
|
||||||
|
"name": "myapp",
|
||||||
|
"projectType": "application",
|
||||||
|
"sourceRoot": "myapp/src",
|
||||||
|
"targets": {
|
||||||
|
"serve": {
|
||||||
|
"configurations": {
|
||||||
|
"development": {
|
||||||
|
"buildTarget": "myapp:build:development",
|
||||||
|
},
|
||||||
|
"production": {
|
||||||
|
"buildTarget": "myapp:build:production",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"defaultConfiguration": "development",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"executor": "@nx/js:node",
|
||||||
|
"options": {
|
||||||
|
"buildTarget": "myapp:build",
|
||||||
|
"runBuildTargetDependencies": false,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"options": {
|
||||||
|
"passWithNoTests": true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"version": "0.0.1",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.app.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"outDir": "out-tsc/myapp",
|
||||||
|
"rootDir": "src",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"eslint.config.js",
|
||||||
|
"eslint.config.cjs",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.spec.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"outDir": "./out-tsc/jest",
|
||||||
|
"types": [
|
||||||
|
"jest",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,3 +1,4 @@
|
|||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
import {
|
import {
|
||||||
addDependenciesToPackageJson,
|
addDependenciesToPackageJson,
|
||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
@ -19,6 +20,7 @@ import {
|
|||||||
updateJson,
|
updateJson,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
updateTsConfigsToJs,
|
updateTsConfigsToJs,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import {
|
import {
|
||||||
determineProjectNameAndRootOptions,
|
determineProjectNameAndRootOptions,
|
||||||
@ -30,7 +32,6 @@ import {
|
|||||||
initGenerator as jsInitGenerator,
|
initGenerator as jsInitGenerator,
|
||||||
tsConfigBaseOptions,
|
tsConfigBaseOptions,
|
||||||
} from '@nx/js';
|
} from '@nx/js';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { esbuildVersion } from '@nx/js/src/utils/versions';
|
import { esbuildVersion } from '@nx/js/src/utils/versions';
|
||||||
import { Linter, lintProjectGenerator } from '@nx/eslint';
|
import { Linter, lintProjectGenerator } from '@nx/eslint';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
@ -54,11 +55,16 @@ import { Schema } from './schema';
|
|||||||
import { hasWebpackPlugin } from '../../utils/has-webpack-plugin';
|
import { hasWebpackPlugin } from '../../utils/has-webpack-plugin';
|
||||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
|
import {
|
||||||
|
isUsingTsSolutionSetup,
|
||||||
|
updateTsconfigFiles,
|
||||||
|
} from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
appProjectRoot: string;
|
appProjectRoot: string;
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
outputPath: string;
|
outputPath: string;
|
||||||
|
isUsingTsSolutionConfig: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWebpackBuildConfig(
|
function getWebpackBuildConfig(
|
||||||
@ -83,7 +89,7 @@ function getWebpackBuildConfig(
|
|||||||
options.appProjectRoot,
|
options.appProjectRoot,
|
||||||
'webpack.config.js'
|
'webpack.config.js'
|
||||||
),
|
),
|
||||||
generatePackageJson: true,
|
generatePackageJson: options.isUsingTsSolutionConfig ? undefined : true,
|
||||||
},
|
},
|
||||||
configurations: {
|
configurations: {
|
||||||
development: {},
|
development: {},
|
||||||
@ -114,7 +120,7 @@ function getEsBuildConfig(
|
|||||||
),
|
),
|
||||||
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
tsConfig: joinPathFragments(options.appProjectRoot, 'tsconfig.app.json'),
|
||||||
assets: [joinPathFragments(project.sourceRoot, 'assets')],
|
assets: [joinPathFragments(project.sourceRoot, 'assets')],
|
||||||
generatePackageJson: true,
|
generatePackageJson: options.isUsingTsSolutionConfig ? undefined : true,
|
||||||
esbuildOptions: {
|
esbuildOptions: {
|
||||||
sourcemap: true,
|
sourcemap: true,
|
||||||
// Generate CJS files as .js so imports can be './foo' rather than './foo.cjs'.
|
// Generate CJS files as .js so imports can be './foo' rather than './foo.cjs'.
|
||||||
@ -198,16 +204,30 @@ function addProject(tree: Tree, options: NormalizedSchema) {
|
|||||||
}
|
}
|
||||||
project.targets.serve = getServeConfig(options);
|
project.targets.serve = getServeConfig(options);
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
writeJson(tree, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||||
|
name: getImportPath(tree, options.name),
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
name: options.name,
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: project.sourceRoot,
|
||||||
|
targets: project.targets,
|
||||||
|
tags: project.tags?.length ? project.tags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(
|
addProjectConfiguration(
|
||||||
tree,
|
tree,
|
||||||
options.name,
|
options.name,
|
||||||
project,
|
project,
|
||||||
options.standaloneConfig
|
options.standaloneConfig
|
||||||
);
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function addAppFiles(tree: Tree, options: NormalizedSchema) {
|
function addAppFiles(tree: Tree, options: NormalizedSchema) {
|
||||||
const sourceRoot = joinPathFragments(options.appProjectRoot, 'src');
|
|
||||||
generateFiles(
|
generateFiles(
|
||||||
tree,
|
tree,
|
||||||
join(__dirname, './files/common'),
|
join(__dirname, './files/common'),
|
||||||
@ -410,10 +430,17 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'node', 'application');
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
|
const jsInitTask = await jsInitGenerator(tree, {
|
||||||
|
...schema,
|
||||||
|
tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
|
||||||
|
skipFormat: true,
|
||||||
|
addTsPlugin: schema.useTsSolution,
|
||||||
|
});
|
||||||
|
tasks.push(jsInitTask);
|
||||||
|
|
||||||
const options = await normalizeOptions(tree, schema);
|
const options = await normalizeOptions(tree, schema);
|
||||||
const tasks: GeneratorCallback[] = [];
|
|
||||||
|
|
||||||
if (options.framework === 'nest') {
|
if (options.framework === 'nest') {
|
||||||
// nx-ignore-next-line
|
// nx-ignore-next-line
|
||||||
@ -442,12 +469,6 @@ export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const jsInitTask = await jsInitGenerator(tree, {
|
|
||||||
...schema,
|
|
||||||
tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
tasks.push(jsInitTask);
|
|
||||||
const initTask = await initGenerator(tree, {
|
const initTask = await initGenerator(tree, {
|
||||||
...schema,
|
...schema,
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
@ -501,6 +522,13 @@ export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
|||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
});
|
});
|
||||||
tasks.push(jestTask);
|
tasks.push(jestTask);
|
||||||
|
// There are no tests by default, so set `--passWithNoTests` to avoid test failure on new project.
|
||||||
|
const projectConfig = readProjectConfiguration(tree, options.name);
|
||||||
|
projectConfig.targets ??= {};
|
||||||
|
projectConfig.targets.test = {
|
||||||
|
options: { passWithNoTests: true },
|
||||||
|
};
|
||||||
|
updateProjectConfiguration(tree, options.name, projectConfig);
|
||||||
} else {
|
} else {
|
||||||
// No need for default spec file if unit testing is not setup.
|
// No need for default spec file if unit testing is not setup.
|
||||||
tree.delete(
|
tree.delete(
|
||||||
@ -544,6 +572,21 @@ export async function applicationGeneratorInternal(tree: Tree, schema: Schema) {
|
|||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
updateTsconfigFiles(
|
||||||
|
tree,
|
||||||
|
options.appProjectRoot,
|
||||||
|
'tsconfig.app.json',
|
||||||
|
{
|
||||||
|
module: 'nodenext',
|
||||||
|
moduleResolution: 'nodenext',
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(() => {
|
tasks.push(() => {
|
||||||
logShowProjectCommand(options.name);
|
logShowProjectCommand(options.name);
|
||||||
});
|
});
|
||||||
@ -594,6 +637,7 @@ async function normalizeOptions(
|
|||||||
'dist',
|
'dist',
|
||||||
options.rootProject ? options.name : appProjectRoot
|
options.rootProject ? options.name : appProjectRoot
|
||||||
),
|
),
|
||||||
|
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,6 +8,7 @@ export interface Schema {
|
|||||||
unitTestRunner?: 'jest' | 'none';
|
unitTestRunner?: 'jest' | 'none';
|
||||||
e2eTestRunner?: 'jest' | 'none';
|
e2eTestRunner?: 'jest' | 'none';
|
||||||
linter?: Linter | LinterType;
|
linter?: Linter | LinterType;
|
||||||
|
formatter?: 'none' | 'prettier';
|
||||||
tags?: string;
|
tags?: string;
|
||||||
frontendProject?: string;
|
frontendProject?: string;
|
||||||
swcJest?: boolean;
|
swcJest?: boolean;
|
||||||
@ -23,6 +24,7 @@ export interface Schema {
|
|||||||
docker?: boolean;
|
docker?: boolean;
|
||||||
isNest?: boolean;
|
isNest?: boolean;
|
||||||
addPlugin?: boolean;
|
addPlugin?: boolean;
|
||||||
|
useTsSolution?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NodeJsFrameWorks = 'express' | 'koa' | 'fastify' | 'nest' | 'none';
|
export type NodeJsFrameWorks = 'express' | 'koa' | 'fastify' | 'nest' | 'none';
|
||||||
|
|||||||
@ -36,14 +36,26 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-priority": "important",
|
||||||
|
"x-prompt": "Which unit test runner would you like to use?"
|
||||||
|
},
|
||||||
|
"e2eTestRunner": {
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["jest", "none"],
|
||||||
|
"description": "Test runner to use for end-to-end tests",
|
||||||
|
"default": "none",
|
||||||
|
"x-priority": "important",
|
||||||
|
"x-prompt": "Which end-to-end test runner would you like to use?"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -109,12 +121,6 @@
|
|||||||
"hidden": true,
|
"hidden": true,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["jest", "none"],
|
|
||||||
"description": "Test runner to use for end to end (e2e) tests",
|
|
||||||
"default": "jest"
|
|
||||||
},
|
|
||||||
"docker": {
|
"docker": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Add a docker build target"
|
"description": "Add a docker build target"
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import 'nx/src/internal-testing-utils/mock-project-graph';
|
import 'nx/src/internal-testing-utils/mock-project-graph';
|
||||||
|
|
||||||
import { Tree } from '@nx/devkit';
|
import { readJson, Tree, updateJson, writeJson } from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { applicationGenerator } from '../application/application';
|
import { applicationGenerator } from '../application/application';
|
||||||
import { e2eProjectGenerator } from './e2e-project';
|
import { e2eProjectGenerator } from './e2e-project';
|
||||||
@ -74,4 +74,92 @@ describe('e2eProjectGenerator', () => {
|
|||||||
"
|
"
|
||||||
`);
|
`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await applicationGenerator(tree, {
|
||||||
|
directory: 'api',
|
||||||
|
framework: 'none',
|
||||||
|
e2eTestRunner: 'none',
|
||||||
|
addPlugin: true,
|
||||||
|
});
|
||||||
|
await e2eProjectGenerator(tree, {
|
||||||
|
projectType: 'server',
|
||||||
|
project: 'api',
|
||||||
|
addPlugin: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./api",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./api-e2e",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(tree.read('api-e2e/jest.config.ts', 'utf-8'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
"export default {
|
||||||
|
displayName: 'api-e2e',
|
||||||
|
preset: '../jest.preset.js',
|
||||||
|
globalSetup: '<rootDir>/src/support/global-setup.ts',
|
||||||
|
globalTeardown: '<rootDir>/src/support/global-teardown.ts',
|
||||||
|
setupFiles: ['<rootDir>/src/support/test-setup.ts'],
|
||||||
|
testEnvironment: 'node',
|
||||||
|
transform: {
|
||||||
|
'^.+\\\\.[tj]s$': [
|
||||||
|
'ts-jest',
|
||||||
|
{
|
||||||
|
tsconfig: '<rootDir>/tsconfig.json',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||||
|
coverageDirectory: '../coverage/api-e2e',
|
||||||
|
};
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'api-e2e/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"noImplicitAny": false,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"outDir": "out-tsc/api-e2e",
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../api",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -12,6 +12,7 @@ import {
|
|||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
import { determineProjectNameAndRootOptions } from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { Linter, lintProjectGenerator } from '@nx/eslint';
|
import { Linter, lintProjectGenerator } from '@nx/eslint';
|
||||||
@ -29,6 +30,9 @@ import {
|
|||||||
} from '@nx/eslint/src/generators/utils/eslint-file';
|
} from '@nx/eslint/src/generators/utils/eslint-file';
|
||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
import { findRootJestPreset } from '@nx/jest/src/utils/config/config-file';
|
import { findRootJestPreset } from '@nx/jest/src/utils/config/config-file';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
import { relative } from 'node:path/posix';
|
||||||
|
|
||||||
export async function e2eProjectGenerator(host: Tree, options: Schema) {
|
export async function e2eProjectGenerator(host: Tree, options: Schema) {
|
||||||
return await e2eProjectGeneratorInternal(host, {
|
return await e2eProjectGeneratorInternal(host, {
|
||||||
@ -44,8 +48,32 @@ export async function e2eProjectGeneratorInternal(
|
|||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
const options = await normalizeOptions(host, _options);
|
const options = await normalizeOptions(host, _options);
|
||||||
const appProject = readProjectConfiguration(host, options.project);
|
const appProject = readProjectConfiguration(host, options.project);
|
||||||
|
const isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||||
|
|
||||||
// TODO(@ndcunningham): This is broken.. the outputs are wrong.. and this isn't using the jest generator
|
// TODO(@ndcunningham): This is broken.. the outputs are wrong.. and this isn't using the jest generator
|
||||||
|
if (isUsingTsSolutionConfig) {
|
||||||
|
writeJson(host, joinPathFragments(options.e2eProjectRoot, 'package.json'), {
|
||||||
|
name: getImportPath(host, options.e2eProjectName),
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
name: options.e2eProjectName,
|
||||||
|
projectType: 'application',
|
||||||
|
implicitDependencies: [options.project],
|
||||||
|
targets: {
|
||||||
|
e2e: {
|
||||||
|
executor: '@nx/jest:jest',
|
||||||
|
outputs: ['{workspaceRoot}/coverage/{e2eProjectRoot}'],
|
||||||
|
options: {
|
||||||
|
jestConfig: `${options.e2eProjectRoot}/jest.config.ts`,
|
||||||
|
passWithNoTests: true,
|
||||||
|
},
|
||||||
|
dependsOn: [`${options.project}:build`],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(host, options.e2eProjectName, {
|
addProjectConfiguration(host, options.e2eProjectName, {
|
||||||
root: options.e2eProjectRoot,
|
root: options.e2eProjectRoot,
|
||||||
implicitDependencies: [options.project],
|
implicitDependencies: [options.project],
|
||||||
@ -62,6 +90,7 @@ export async function e2eProjectGeneratorInternal(
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
// TODO(@nicholas): Find a better way to get build target
|
// TODO(@nicholas): Find a better way to get build target
|
||||||
|
|
||||||
// We remove the 'test' target from the e2e project because it is not needed
|
// We remove the 'test' target from the e2e project because it is not needed
|
||||||
@ -91,6 +120,9 @@ export async function e2eProjectGeneratorInternal(
|
|||||||
}
|
}
|
||||||
|
|
||||||
const jestPreset = findRootJestPreset(host) ?? 'jest.preset.js';
|
const jestPreset = findRootJestPreset(host) ?? 'jest.preset.js';
|
||||||
|
const tsConfigFile = isUsingTsSolutionConfig
|
||||||
|
? 'tsconfig.json'
|
||||||
|
: 'tsconfig.spec.json';
|
||||||
if (options.projectType === 'server') {
|
if (options.projectType === 'server') {
|
||||||
generateFiles(
|
generateFiles(
|
||||||
host,
|
host,
|
||||||
@ -99,6 +131,7 @@ export async function e2eProjectGeneratorInternal(
|
|||||||
{
|
{
|
||||||
...options,
|
...options,
|
||||||
...names(options.rootProject ? 'server' : options.project),
|
...names(options.rootProject ? 'server' : options.project),
|
||||||
|
tsConfigFile,
|
||||||
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot),
|
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot),
|
||||||
jestPreset,
|
jestPreset,
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
@ -113,6 +146,7 @@ export async function e2eProjectGeneratorInternal(
|
|||||||
{
|
{
|
||||||
...options,
|
...options,
|
||||||
...names(options.rootProject ? 'server' : options.project),
|
...names(options.rootProject ? 'server' : options.project),
|
||||||
|
tsConfigFile,
|
||||||
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot),
|
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot),
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
}
|
}
|
||||||
@ -128,6 +162,7 @@ export async function e2eProjectGeneratorInternal(
|
|||||||
...options,
|
...options,
|
||||||
...names(options.rootProject ? 'cli' : options.project),
|
...names(options.rootProject ? 'cli' : options.project),
|
||||||
mainFile,
|
mainFile,
|
||||||
|
tsConfigFile,
|
||||||
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot),
|
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot),
|
||||||
jestPreset,
|
jestPreset,
|
||||||
tmpl: '',
|
tmpl: '',
|
||||||
@ -135,6 +170,34 @@ export async function e2eProjectGeneratorInternal(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isUsingTsSolutionConfig) {
|
||||||
|
generateFiles(
|
||||||
|
host,
|
||||||
|
path.join(__dirname, 'files/ts-solution'),
|
||||||
|
options.e2eProjectRoot,
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
relativeProjectReferencePath: relative(
|
||||||
|
options.e2eProjectRoot,
|
||||||
|
appProject.root
|
||||||
|
),
|
||||||
|
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot),
|
||||||
|
tmpl: '',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
generateFiles(
|
||||||
|
host,
|
||||||
|
path.join(__dirname, 'files/non-ts-solution'),
|
||||||
|
options.e2eProjectRoot,
|
||||||
|
{
|
||||||
|
...options,
|
||||||
|
offsetFromRoot: offsetFromRoot(options.e2eProjectRoot),
|
||||||
|
tmpl: '',
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
// axios is more than likely used in the application code, so install it as a regular dependency.
|
// axios is more than likely used in the application code, so install it as a regular dependency.
|
||||||
const installTask = addDependenciesToPackageJson(
|
const installTask = addDependenciesToPackageJson(
|
||||||
host,
|
host,
|
||||||
@ -171,6 +234,17 @@ export async function e2eProjectGeneratorInternal(
|
|||||||
await formatFiles(host);
|
await formatFiles(host);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (isUsingTsSolutionConfig) {
|
||||||
|
updateJson(host, 'tsconfig.json', (json) => {
|
||||||
|
json.references ??= [];
|
||||||
|
const e2eRef = `./${options.e2eProjectRoot}`;
|
||||||
|
if (!json.references.find((ref) => ref.path === e2eRef)) {
|
||||||
|
json.references.push({ path: e2eRef });
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(() => {
|
tasks.push(() => {
|
||||||
logShowProjectCommand(options.e2eProjectName);
|
logShowProjectCommand(options.e2eProjectName);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,7 +5,7 @@ export default {
|
|||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.[tj]s$': ['ts-jest', {
|
'^.+\\.[tj]s$': ['ts-jest', {
|
||||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
tsconfig: '<rootDir>/<%= tsConfigFile %>',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "./tsconfig.json",
|
|
||||||
"compilerOptions": {
|
|
||||||
"outDir": "<%= offsetFromRoot %>/dist/out-tsc",
|
|
||||||
"module": "commonjs",
|
|
||||||
"types": ["jest", "node"]
|
|
||||||
},
|
|
||||||
"include": [
|
|
||||||
"jest.config.ts",
|
|
||||||
"src/**/*.ts"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
@ -7,7 +7,7 @@ export default {
|
|||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
transform: {
|
transform: {
|
||||||
'^.+\\.[tj]s$': ['ts-jest', {
|
'^.+\\.[tj]s$': ['ts-jest', {
|
||||||
tsconfig: '<rootDir>/tsconfig.spec.json',
|
tsconfig: '<rootDir>/<%= tsConfigFile %>',
|
||||||
}],
|
}],
|
||||||
},
|
},
|
||||||
moduleFileExtensions: ['ts', 'js', 'html'],
|
moduleFileExtensions: ['ts', 'js', 'html'],
|
||||||
|
|||||||
@ -1,13 +0,0 @@
|
|||||||
{
|
|
||||||
"extends": "<%= offsetFromRoot %><% if (rootProject) { %>tsconfig.json<% } else { %>tsconfig.base.json<% } %>",
|
|
||||||
"files": [],
|
|
||||||
"include": [],
|
|
||||||
"references": [
|
|
||||||
{
|
|
||||||
"path": "./tsconfig.spec.json"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"compilerOptions": {
|
|
||||||
"esModuleInterop": true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"extends": "<%= offsetFromRoot %>tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "out-tsc/<%= e2eProjectName %>",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"noUnusedLocals": false,
|
||||||
|
"noImplicitAny": false
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.ts"
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{ "path": "<%= relativeProjectReferencePath %>" }
|
||||||
|
]
|
||||||
|
}
|
||||||
@ -6,7 +6,6 @@ import {
|
|||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { nxVersion } from '../../utils/versions';
|
import { nxVersion } from '../../utils/versions';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
|
|
||||||
@ -27,8 +26,6 @@ function updateDependencies(tree: Tree, options: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function initGenerator(tree: Tree, options: Schema) {
|
export async function initGenerator(tree: Tree, options: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'node', 'init');
|
|
||||||
|
|
||||||
let installTask: GeneratorCallback = () => {};
|
let installTask: GeneratorCallback = () => {};
|
||||||
if (!options.skipPackageJson) {
|
if (!options.skipPackageJson) {
|
||||||
installTask = updateDependencies(tree, options);
|
installTask = updateDependencies(tree, options);
|
||||||
|
|||||||
@ -1,4 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "<%= importPath %>",
|
|
||||||
"version": "0.0.1"
|
|
||||||
}
|
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"rootDir": "src",
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"outDir": "dist",
|
||||||
|
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
||||||
|
"emitDeclarationOnly": false,
|
||||||
|
"types": ["node"]
|
||||||
|
},
|
||||||
|
"exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"],
|
||||||
|
"include": ["src/**/*.ts"]
|
||||||
|
}
|
||||||
@ -5,6 +5,8 @@ import {
|
|||||||
readJson,
|
readJson,
|
||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
|
updateJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
|
|
||||||
@ -474,7 +476,7 @@ describe('lib', () => {
|
|||||||
'src/**/*.js',
|
'src/**/*.js',
|
||||||
]);
|
]);
|
||||||
expect(readJson(tree, 'my-lib/tsconfig.lib.json').exclude).toEqual([
|
expect(readJson(tree, 'my-lib/tsconfig.lib.json').exclude).toEqual([
|
||||||
'jest.config.ts',
|
'jest.config.js',
|
||||||
'src/**/*.spec.ts',
|
'src/**/*.spec.ts',
|
||||||
'src/**/*.test.ts',
|
'src/**/*.test.ts',
|
||||||
'src/**/*.spec.js',
|
'src/**/*.spec.js',
|
||||||
@ -517,4 +519,163 @@ describe('lib', () => {
|
|||||||
expect(tree.exists('my-dir/my-lib/src/lib/my-lib.spec.js')).toBeTruthy();
|
expect(tree.exists('my-dir/my-lib/src/lib/my-lib.spec.js')).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'mylib',
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
addPlugin: true,
|
||||||
|
} as Schema);
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./mylib",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'mylib/package.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"dependencies": {},
|
||||||
|
"main": "./src/index.ts",
|
||||||
|
"name": "@proj/mylib",
|
||||||
|
"nx": {
|
||||||
|
"name": "mylib",
|
||||||
|
"projectType": "library",
|
||||||
|
"sourceRoot": "mylib/src",
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"types": "./src/index.ts",
|
||||||
|
"version": "0.0.1",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'mylib/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.lib.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'mylib/tsconfig.lib.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"baseUrl": ".",
|
||||||
|
"emitDeclarationOnly": false,
|
||||||
|
"module": "nodenext",
|
||||||
|
"moduleResolution": "nodenext",
|
||||||
|
"outDir": "dist",
|
||||||
|
"rootDir": "src",
|
||||||
|
"tsBuildInfoFile": "dist/tsconfig.lib.tsbuildinfo",
|
||||||
|
"types": [
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.ts",
|
||||||
|
],
|
||||||
|
"references": [],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'mylib/tsconfig.spec.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"outDir": "./out-tsc/jest",
|
||||||
|
"types": [
|
||||||
|
"jest",
|
||||||
|
"node",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"jest.config.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.lib.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set correct options for swc', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
directory: 'mylib',
|
||||||
|
buildable: true,
|
||||||
|
compiler: 'swc',
|
||||||
|
unitTestRunner: 'jest',
|
||||||
|
addPlugin: true,
|
||||||
|
} as Schema);
|
||||||
|
|
||||||
|
expect(readJson(tree, 'mylib/package.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"tslib": "^2.3.0",
|
||||||
|
},
|
||||||
|
"main": "./dist/index.js",
|
||||||
|
"name": "@proj/mylib",
|
||||||
|
"nx": {
|
||||||
|
"name": "mylib",
|
||||||
|
"projectType": "library",
|
||||||
|
"sourceRoot": "mylib/src",
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"executor": "@nx/js:swc",
|
||||||
|
"options": {
|
||||||
|
"main": "mylib/src/index.ts",
|
||||||
|
"outputPath": "mylib/dist",
|
||||||
|
"packageJson": "mylib/package.json",
|
||||||
|
"stripLeadingPaths": true,
|
||||||
|
"tsConfig": "mylib/tsconfig.lib.json",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{options.outputPath}",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"private": true,
|
||||||
|
"type": "commonjs",
|
||||||
|
"typings": "./dist/index.d.ts",
|
||||||
|
"version": "0.0.1",
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -3,6 +3,7 @@ import {
|
|||||||
formatFiles,
|
formatFiles,
|
||||||
generateFiles,
|
generateFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
|
installPackagesTask,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
names,
|
names,
|
||||||
offsetFromRoot,
|
offsetFromRoot,
|
||||||
@ -13,6 +14,7 @@ import {
|
|||||||
Tree,
|
Tree,
|
||||||
updateProjectConfiguration,
|
updateProjectConfiguration,
|
||||||
updateTsConfigsToJs,
|
updateTsConfigsToJs,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import {
|
import {
|
||||||
determineProjectNameAndRootOptions,
|
determineProjectNameAndRootOptions,
|
||||||
@ -21,12 +23,13 @@ import {
|
|||||||
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
import { libraryGenerator as jsLibraryGenerator } from '@nx/js';
|
||||||
import { addSwcConfig } from '@nx/js/src/utils/swc/add-swc-config';
|
import { addSwcConfig } from '@nx/js/src/utils/swc/add-swc-config';
|
||||||
import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies';
|
import { addSwcDependencies } from '@nx/js/src/utils/swc/add-swc-dependencies';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { tslibVersion, typesNodeVersion } from '../../utils/versions';
|
import { tslibVersion, typesNodeVersion } from '../../utils/versions';
|
||||||
import { initGenerator } from '../init/init';
|
import { initGenerator } from '../init/init';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/target-defaults-utils';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
fileName: string;
|
fileName: string;
|
||||||
@ -34,6 +37,7 @@ export interface NormalizedSchema extends Schema {
|
|||||||
projectRoot: string;
|
projectRoot: string;
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
compiler: 'swc' | 'tsc';
|
compiler: 'swc' | 'tsc';
|
||||||
|
isUsingTsSolutionConfig: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function libraryGenerator(tree: Tree, schema: Schema) {
|
export async function libraryGenerator(tree: Tree, schema: Schema) {
|
||||||
@ -44,15 +48,8 @@ export async function libraryGenerator(tree: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'node', 'library');
|
|
||||||
|
|
||||||
const options = await normalizeOptions(tree, schema);
|
const options = await normalizeOptions(tree, schema);
|
||||||
const tasks: GeneratorCallback[] = [
|
const tasks: GeneratorCallback[] = [];
|
||||||
await initGenerator(tree, {
|
|
||||||
...options,
|
|
||||||
skipFormat: true,
|
|
||||||
}),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (options.publishable === true && !schema.importPath) {
|
if (options.publishable === true && !schema.importPath) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -60,16 +57,40 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const libraryInstall = await jsLibraryGenerator(tree, {
|
// Create `package.json` first because @nx/js:lib generator will update it.
|
||||||
...options,
|
if (
|
||||||
|
options.isUsingTsSolutionConfig ||
|
||||||
|
options.publishable ||
|
||||||
|
options.buildable
|
||||||
|
) {
|
||||||
|
writeJson(tree, joinPathFragments(options.projectRoot, 'package.json'), {
|
||||||
|
name: getImportPath(tree, options.name),
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.push(
|
||||||
|
await jsLibraryGenerator(tree, {
|
||||||
|
...schema,
|
||||||
bundler: schema.buildable || schema.publishable ? 'tsc' : 'none',
|
bundler: schema.buildable || schema.publishable ? 'tsc' : 'none',
|
||||||
includeBabelRc: schema.babelJest,
|
includeBabelRc: schema.babelJest,
|
||||||
importPath: options.importPath,
|
importPath: schema.importPath,
|
||||||
testEnvironment: 'node',
|
testEnvironment: 'node',
|
||||||
skipFormat: true,
|
skipFormat: true,
|
||||||
setParserOptionsProject: options.setParserOptionsProject,
|
setParserOptionsProject: schema.setParserOptionsProject,
|
||||||
});
|
useProjectJson: !options.isUsingTsSolutionConfig,
|
||||||
tasks.push(libraryInstall);
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
tasks.push(
|
||||||
|
await initGenerator(tree, {
|
||||||
|
...options,
|
||||||
|
skipFormat: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
createFiles(tree, options);
|
createFiles(tree, options);
|
||||||
|
|
||||||
if (options.js) {
|
if (options.js) {
|
||||||
@ -79,6 +100,11 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
|||||||
|
|
||||||
tasks.push(ensureDependencies(tree));
|
tasks.push(ensureDependencies(tree));
|
||||||
|
|
||||||
|
// Always run install to link packages.
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
tasks.push(() => installPackagesTask(tree, true));
|
||||||
|
}
|
||||||
|
|
||||||
if (!schema.skipFormat) {
|
if (!schema.skipFormat) {
|
||||||
await formatFiles(tree);
|
await formatFiles(tree);
|
||||||
}
|
}
|
||||||
@ -129,6 +155,7 @@ async function normalizeOptions(
|
|||||||
projectRoot,
|
projectRoot,
|
||||||
parsedTags,
|
parsedTags,
|
||||||
importPath,
|
importPath,
|
||||||
|
isUsingTsSolutionConfig: isUsingTsSolutionSetup(tree),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,9 +176,6 @@ function createFiles(tree: Tree, options: NormalizedSchema) {
|
|||||||
join(options.projectRoot, `./src/lib/${options.fileName}.spec.ts`)
|
join(options.projectRoot, `./src/lib/${options.fileName}.spec.ts`)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (!options.publishable && !options.buildable) {
|
|
||||||
tree.delete(join(options.projectRoot, 'package.json'));
|
|
||||||
}
|
|
||||||
if (options.js) {
|
if (options.js) {
|
||||||
toJS(tree);
|
toJS(tree);
|
||||||
}
|
}
|
||||||
@ -167,20 +191,29 @@ function updateProject(tree: Tree, options: NormalizedSchema) {
|
|||||||
|
|
||||||
project.targets = project.targets || {};
|
project.targets = project.targets || {};
|
||||||
addBuildTargetDefaults(tree, `@nx/js:${options.compiler}`);
|
addBuildTargetDefaults(tree, `@nx/js:${options.compiler}`);
|
||||||
|
|
||||||
|
// For TS solution, we want tsc build to be inferred by `@nx/js/typescript` plugin.
|
||||||
|
if (!options.isUsingTsSolutionConfig || options.compiler === 'swc') {
|
||||||
project.targets.build = {
|
project.targets.build = {
|
||||||
executor: `@nx/js:${options.compiler}`,
|
executor: `@nx/js:${options.compiler}`,
|
||||||
outputs: ['{options.outputPath}'],
|
outputs: ['{options.outputPath}'],
|
||||||
options: {
|
options: {
|
||||||
outputPath: joinPathFragments(
|
outputPath: options.isUsingTsSolutionConfig
|
||||||
|
? joinPathFragments(options.projectRoot, 'dist')
|
||||||
|
: joinPathFragments(
|
||||||
'dist',
|
'dist',
|
||||||
rootProject ? options.projectName : options.projectRoot
|
rootProject ? options.projectName : options.projectRoot
|
||||||
),
|
),
|
||||||
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
tsConfig: `${options.projectRoot}/tsconfig.lib.json`,
|
||||||
packageJson: `${options.projectRoot}/package.json`,
|
packageJson: `${options.projectRoot}/package.json`,
|
||||||
main: `${options.projectRoot}/src/index` + (options.js ? '.js' : '.ts'),
|
main: `${options.projectRoot}/src/index` + (options.js ? '.js' : '.ts'),
|
||||||
assets: [`${options.projectRoot}/*.md`],
|
assets: options.isUsingTsSolutionConfig
|
||||||
|
? undefined
|
||||||
|
: [`${options.projectRoot}/*.md`],
|
||||||
|
stripLeadingPaths: options.isUsingTsSolutionConfig ? true : undefined,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if (options.compiler === 'swc') {
|
if (options.compiler === 'swc') {
|
||||||
addSwcDependencies(tree);
|
addSwcDependencies(tree);
|
||||||
|
|||||||
@ -36,14 +36,18 @@
|
|||||||
"linter": {
|
"linter": {
|
||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["jest", "none"],
|
"enum": ["jest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"default": "jest"
|
"default": "none",
|
||||||
|
"x-prompt": "Which unit test runner would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"tags": {
|
"tags": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
@ -69,7 +73,7 @@
|
|||||||
},
|
},
|
||||||
"buildable": {
|
"buildable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": true,
|
||||||
"description": "Generate a buildable library.",
|
"description": "Generate a buildable library.",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
|
|||||||
@ -108,7 +108,6 @@ exports[`app generated files content - as-provided - my-app general application
|
|||||||
|
|
||||||
exports[`app generated files content - as-provided - my-app general application should configure tsconfig and project.json correctly 2`] = `
|
exports[`app generated files content - as-provided - my-app general application should configure tsconfig and project.json correctly 2`] = `
|
||||||
"{
|
"{
|
||||||
"compilerOptions": {},
|
|
||||||
"files": [],
|
"files": [],
|
||||||
"include": [".nuxt/nuxt.d.ts"],
|
"include": [".nuxt/nuxt.d.ts"],
|
||||||
"references": [
|
"references": [
|
||||||
@ -190,7 +189,6 @@ exports[`app generated files content - as-provided - my-app general application
|
|||||||
|
|
||||||
exports[`app generated files content - as-provided - my-app general application should configure vitest correctly 3`] = `
|
exports[`app generated files content - as-provided - my-app general application should configure vitest correctly 3`] = `
|
||||||
"{
|
"{
|
||||||
"compilerOptions": {},
|
|
||||||
"files": [],
|
"files": [],
|
||||||
"include": [".nuxt/nuxt.d.ts"],
|
"include": [".nuxt/nuxt.d.ts"],
|
||||||
"references": [
|
"references": [
|
||||||
@ -469,7 +467,6 @@ exports[`app generated files content - as-provided - myApp general application s
|
|||||||
|
|
||||||
exports[`app generated files content - as-provided - myApp general application should configure tsconfig and project.json correctly 2`] = `
|
exports[`app generated files content - as-provided - myApp general application should configure tsconfig and project.json correctly 2`] = `
|
||||||
"{
|
"{
|
||||||
"compilerOptions": {},
|
|
||||||
"files": [],
|
"files": [],
|
||||||
"include": [".nuxt/nuxt.d.ts"],
|
"include": [".nuxt/nuxt.d.ts"],
|
||||||
"references": [
|
"references": [
|
||||||
@ -551,7 +548,6 @@ exports[`app generated files content - as-provided - myApp general application s
|
|||||||
|
|
||||||
exports[`app generated files content - as-provided - myApp general application should configure vitest correctly 3`] = `
|
exports[`app generated files content - as-provided - myApp general application should configure vitest correctly 3`] = `
|
||||||
"{
|
"{
|
||||||
"compilerOptions": {},
|
|
||||||
"files": [],
|
"files": [],
|
||||||
"include": [".nuxt/nuxt.d.ts"],
|
"include": [".nuxt/nuxt.d.ts"],
|
||||||
"references": [
|
"references": [
|
||||||
|
|||||||
@ -1,7 +1,13 @@
|
|||||||
import 'nx/src/internal-testing-utils/mock-project-graph';
|
import 'nx/src/internal-testing-utils/mock-project-graph';
|
||||||
|
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { Tree, readJson, readProjectConfiguration } from '@nx/devkit';
|
import {
|
||||||
|
Tree,
|
||||||
|
readJson,
|
||||||
|
readProjectConfiguration,
|
||||||
|
updateJson,
|
||||||
|
writeJson,
|
||||||
|
} from '@nx/devkit';
|
||||||
import { applicationGenerator } from './application';
|
import { applicationGenerator } from './application';
|
||||||
|
|
||||||
describe('app', () => {
|
describe('app', () => {
|
||||||
@ -194,4 +200,173 @@ describe('app', () => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await applicationGenerator(tree, {
|
||||||
|
directory: 'myapp',
|
||||||
|
e2eTestRunner: 'playwright',
|
||||||
|
unitTestRunner: 'vitest',
|
||||||
|
linter: 'eslint',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tree.read('myapp/vite.config.ts', 'utf-8')).toMatchInlineSnapshot(
|
||||||
|
`null`
|
||||||
|
);
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./myapp-e2e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./myapp",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.app.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "vue",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "out-tsc/myapp",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"rootDir": "src",
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"eslint.config.js",
|
||||||
|
"eslint.config.cjs",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
".nuxt/nuxt.d.ts",
|
||||||
|
"src/**/*",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp/tsconfig.spec.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"composite": true,
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "vue",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "./out-tsc/vitest",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"types": [
|
||||||
|
"vitest/globals",
|
||||||
|
"vitest/importMeta",
|
||||||
|
"vite/client",
|
||||||
|
"node",
|
||||||
|
"vitest",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
".nuxt/nuxt.d.ts",
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'myapp-e2e/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"allowJs": true,
|
||||||
|
"outDir": "dist",
|
||||||
|
"sourceMap": false,
|
||||||
|
"tsBuildInfoFile": "dist/tsconfig.tsbuildinfo",
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"eslint.config.js",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
"eslint.config.cjs",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.js",
|
||||||
|
"playwright.config.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../myapp",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import {
|
|||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
toJS,
|
toJS,
|
||||||
Tree,
|
Tree,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import nuxtInitGenerator from '../init/init';
|
import nuxtInitGenerator from '../init/init';
|
||||||
@ -18,7 +19,6 @@ import {
|
|||||||
getRelativePathToRootTsConfig,
|
getRelativePathToRootTsConfig,
|
||||||
initGenerator as jsInitGenerator,
|
initGenerator as jsInitGenerator,
|
||||||
} from '@nx/js';
|
} from '@nx/js';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { updateGitIgnore } from '../../utils/update-gitignore';
|
import { updateGitIgnore } from '../../utils/update-gitignore';
|
||||||
import { Linter } from '@nx/eslint';
|
import { Linter } from '@nx/eslint';
|
||||||
import { addE2e } from './lib/add-e2e';
|
import { addE2e } from './lib/add-e2e';
|
||||||
@ -32,12 +32,20 @@ import {
|
|||||||
getNxCloudAppOnBoardingUrl,
|
getNxCloudAppOnBoardingUrl,
|
||||||
createNxCloudOnboardingURLForWelcomeApp,
|
createNxCloudOnboardingURLForWelcomeApp,
|
||||||
} from 'nx/src/nx-cloud/utilities/onboarding';
|
} from 'nx/src/nx-cloud/utilities/onboarding';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function applicationGenerator(tree: Tree, schema: Schema) {
|
export async function applicationGenerator(tree: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'nuxt', 'application');
|
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
|
const jsInitTask = await jsInitGenerator(tree, {
|
||||||
|
...schema,
|
||||||
|
tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
|
||||||
|
skipFormat: true,
|
||||||
|
addTsPlugin: schema.useTsSolution,
|
||||||
|
});
|
||||||
|
tasks.push(jsInitTask);
|
||||||
|
|
||||||
const options = await normalizeOptions(tree, schema);
|
const options = await normalizeOptions(tree, schema);
|
||||||
|
|
||||||
const projectOffsetFromRoot = offsetFromRoot(options.appProjectRoot);
|
const projectOffsetFromRoot = offsetFromRoot(options.appProjectRoot);
|
||||||
@ -51,20 +59,29 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|||||||
onBoardingStatus === 'unclaimed' &&
|
onBoardingStatus === 'unclaimed' &&
|
||||||
(await getNxCloudAppOnBoardingUrl(options.nxCloudToken));
|
(await getNxCloudAppOnBoardingUrl(options.nxCloudToken));
|
||||||
|
|
||||||
const jsInitTask = await jsInitGenerator(tree, {
|
|
||||||
...schema,
|
|
||||||
tsConfigName: schema.rootProject ? 'tsconfig.json' : 'tsconfig.base.json',
|
|
||||||
skipFormat: true,
|
|
||||||
});
|
|
||||||
tasks.push(jsInitTask);
|
|
||||||
tasks.push(ensureDependencies(tree, options));
|
tasks.push(ensureDependencies(tree, options));
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
writeJson(tree, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||||
|
name: getImportPath(tree, options.name),
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
name: options.name,
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: `${options.appProjectRoot}/src`,
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(tree, options.projectName, {
|
addProjectConfiguration(tree, options.projectName, {
|
||||||
root: options.appProjectRoot,
|
root: options.appProjectRoot,
|
||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
sourceRoot: `${options.appProjectRoot}/src`,
|
sourceRoot: `${options.appProjectRoot}/src`,
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
targets: {},
|
targets: {},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
generateFiles(
|
generateFiles(
|
||||||
tree,
|
tree,
|
||||||
@ -111,6 +128,7 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|||||||
projectRoot: options.appProjectRoot,
|
projectRoot: options.appProjectRoot,
|
||||||
rootProject: options.rootProject,
|
rootProject: options.rootProject,
|
||||||
unitTestRunner: options.unitTestRunner,
|
unitTestRunner: options.unitTestRunner,
|
||||||
|
isUsingTsSolutionConfig: options.isUsingTsSolutionConfig,
|
||||||
},
|
},
|
||||||
getRelativePathToRootTsConfig(tree, options.appProjectRoot)
|
getRelativePathToRootTsConfig(tree, options.appProjectRoot)
|
||||||
);
|
);
|
||||||
@ -168,6 +186,24 @@ export async function applicationGenerator(tree: Tree, schema: Schema) {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
updateTsconfigFiles(
|
||||||
|
tree,
|
||||||
|
options.appProjectRoot,
|
||||||
|
'tsconfig.app.json',
|
||||||
|
{
|
||||||
|
jsx: 'preserve',
|
||||||
|
jsxImportSource: 'vue',
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
resolveJsonModule: true,
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(() => {
|
tasks.push(() => {
|
||||||
logShowProjectCommand(options.projectName);
|
logShowProjectCommand(options.projectName);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import {
|
|||||||
ensureProjectName,
|
ensureProjectName,
|
||||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { NormalizedSchema, Schema } from '../schema';
|
import { NormalizedSchema, Schema } from '../schema';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function normalizeOptions(
|
export async function normalizeOptions(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -35,6 +36,7 @@ export async function normalizeOptions(
|
|||||||
e2eProjectRoot,
|
e2eProjectRoot,
|
||||||
parsedTags,
|
parsedTags,
|
||||||
style: options.style ?? 'none',
|
style: options.style ?? 'none',
|
||||||
|
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||||
} as NormalizedSchema;
|
} as NormalizedSchema;
|
||||||
|
|
||||||
normalized.unitTestRunner ??= 'vitest';
|
normalized.unitTestRunner ??= 'vitest';
|
||||||
|
|||||||
@ -4,6 +4,7 @@ export interface Schema {
|
|||||||
directory: string;
|
directory: string;
|
||||||
name?: string;
|
name?: string;
|
||||||
linter?: Linter | LinterType;
|
linter?: Linter | LinterType;
|
||||||
|
formatter?: 'none' | 'prettier';
|
||||||
skipFormat?: boolean;
|
skipFormat?: boolean;
|
||||||
unitTestRunner?: 'vitest' | 'none';
|
unitTestRunner?: 'vitest' | 'none';
|
||||||
e2eTestRunner?: 'cypress' | 'playwright' | 'none';
|
e2eTestRunner?: 'cypress' | 'playwright' | 'none';
|
||||||
@ -14,6 +15,7 @@ export interface Schema {
|
|||||||
setParserOptionsProject?: boolean;
|
setParserOptionsProject?: boolean;
|
||||||
style?: 'css' | 'scss' | 'less' | 'none';
|
style?: 'css' | 'scss' | 'less' | 'none';
|
||||||
nxCloudToken?: string;
|
nxCloudToken?: string;
|
||||||
|
useTsSolution?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
@ -22,4 +24,5 @@ export interface NormalizedSchema extends Schema {
|
|||||||
e2eProjectName: string;
|
e2eProjectName: string;
|
||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
|
isUsingTsSolutionConfig: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,24 +22,27 @@
|
|||||||
"pattern": "^[a-zA-Z][^:]*$",
|
"pattern": "^[a-zA-Z][^:]*$",
|
||||||
"x-priority": "important"
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"linter": {
|
|
||||||
"description": "The tool to use for running lint checks.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["eslint"],
|
|
||||||
"default": "eslint"
|
|
||||||
},
|
|
||||||
"skipFormat": {
|
"skipFormat": {
|
||||||
"description": "Skip formatting files.",
|
"description": "Skip formatting files.",
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "none"],
|
||||||
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "none"],
|
"enum": ["vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"x-prompt": "Which unit test runner would you like to use?",
|
"x-prompt": "Which unit test runner would you like to use?",
|
||||||
"default": "none"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"e2eTestRunner": {
|
"e2eTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
import { createProjectGraphAsync, GeneratorCallback, Tree } from '@nx/devkit';
|
import { createProjectGraphAsync, GeneratorCallback, Tree } from '@nx/devkit';
|
||||||
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
|
import { addPluginV1 } from '@nx/devkit/src/utils/add-plugin';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
|
|
||||||
import { createNodes } from '../../plugins/plugin';
|
import { createNodes } from '../../plugins/plugin';
|
||||||
import { InitSchema } from './schema';
|
import { InitSchema } from './schema';
|
||||||
import { updateDependencies } from './lib/utils';
|
import { updateDependencies } from './lib/utils';
|
||||||
|
|
||||||
export async function nuxtInitGenerator(host: Tree, schema: InitSchema) {
|
export async function nuxtInitGenerator(host: Tree, schema: InitSchema) {
|
||||||
assertNotUsingTsSolutionSetup(host, 'nuxt', 'init');
|
|
||||||
|
|
||||||
await addPluginV1(
|
await addPluginV1(
|
||||||
host,
|
host,
|
||||||
await createProjectGraphAsync(),
|
await createProjectGraphAsync(),
|
||||||
|
|||||||
@ -7,14 +7,14 @@ export function createTsConfig(
|
|||||||
projectRoot: string;
|
projectRoot: string;
|
||||||
rootProject?: boolean;
|
rootProject?: boolean;
|
||||||
unitTestRunner?: string;
|
unitTestRunner?: string;
|
||||||
|
isUsingTsSolutionConfig: boolean;
|
||||||
},
|
},
|
||||||
relativePathToRootTsConfig: string
|
relativePathToRootTsConfig: string
|
||||||
) {
|
) {
|
||||||
createAppTsConfig(host, options);
|
createAppTsConfig(host, options);
|
||||||
const json = {
|
const json = {
|
||||||
compilerOptions: {},
|
|
||||||
files: [],
|
files: [],
|
||||||
include: ['.nuxt/nuxt.d.ts'],
|
include: options.isUsingTsSolutionConfig ? undefined : ['.nuxt/nuxt.d.ts'],
|
||||||
references: [
|
references: [
|
||||||
{
|
{
|
||||||
path: './tsconfig.app.json',
|
path: './tsconfig.app.json',
|
||||||
|
|||||||
@ -97,7 +97,12 @@ export async function configurationGeneratorInternal(
|
|||||||
if (isTsSolutionSetup) {
|
if (isTsSolutionSetup) {
|
||||||
// skip eslint from typechecking since it extends from root file that is outside rootDir
|
// skip eslint from typechecking since it extends from root file that is outside rootDir
|
||||||
if (options.linter === 'eslint') {
|
if (options.linter === 'eslint') {
|
||||||
tsconfig.exclude = ['dist', 'eslint.config.js'];
|
tsconfig.exclude = [
|
||||||
|
'dist',
|
||||||
|
'eslint.config.js',
|
||||||
|
'eslint.config.mjs',
|
||||||
|
'eslint.config.cjs',
|
||||||
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
tsconfig.compilerOptions.outDir = 'dist';
|
tsconfig.compilerOptions.outDir = 'dist';
|
||||||
|
|||||||
@ -1419,6 +1419,8 @@ describe('app', () => {
|
|||||||
"exclude": [
|
"exclude": [
|
||||||
"dist",
|
"dist",
|
||||||
"eslint.config.js",
|
"eslint.config.js",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
"eslint.config.cjs",
|
||||||
],
|
],
|
||||||
"extends": "../tsconfig.base.json",
|
"extends": "../tsconfig.base.json",
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
@ -1001,7 +1001,7 @@ module.exports = withNx(
|
|||||||
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||||
reporters: ['default'],
|
reporters: ['default'],
|
||||||
coverage: {
|
coverage: {
|
||||||
reportsDirectory: '../coverage/mylib',
|
reportsDirectory: './test-output/vitest/coverage',
|
||||||
provider: 'v8',
|
provider: 'v8',
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
@ -507,6 +507,8 @@ describe('Remix Application', () => {
|
|||||||
"exclude": [
|
"exclude": [
|
||||||
"dist",
|
"dist",
|
||||||
"eslint.config.js",
|
"eslint.config.js",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
"eslint.config.cjs",
|
||||||
],
|
],
|
||||||
"extends": "../tsconfig.base.json",
|
"extends": "../tsconfig.base.json",
|
||||||
"include": [
|
"include": [
|
||||||
|
|||||||
@ -460,8 +460,9 @@ export function createOrEditViteConfig(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
const reportsDirectory =
|
const reportsDirectory = isUsingTsPlugin
|
||||||
projectRoot === '.'
|
? './test-output/vitest/coverage'
|
||||||
|
: projectRoot === '.'
|
||||||
? `./coverage/${options.project}`
|
? `./coverage/${options.project}`
|
||||||
: `${offsetFromRoot(projectRoot)}coverage/${projectRoot}`;
|
: `${offsetFromRoot(projectRoot)}coverage/${projectRoot}`;
|
||||||
|
|
||||||
|
|||||||
@ -361,6 +361,7 @@ exports[`application generator should set up project correctly with given option
|
|||||||
"test/src/app/NxWelcome.vue",
|
"test/src/app/NxWelcome.vue",
|
||||||
"test/src/main.ts",
|
"test/src/main.ts",
|
||||||
"test/src/styles.css",
|
"test/src/styles.css",
|
||||||
|
"test/src/vue-shims.d.ts",
|
||||||
"test/tsconfig.app.json",
|
"test/tsconfig.app.json",
|
||||||
"test/tsconfig.json",
|
"test/tsconfig.json",
|
||||||
"test/tsconfig.spec.json",
|
"test/tsconfig.spec.json",
|
||||||
|
|||||||
@ -6,6 +6,9 @@ import {
|
|||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
updateNxJson,
|
updateNxJson,
|
||||||
|
updateJson,
|
||||||
|
writeJson,
|
||||||
|
readJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
|
|
||||||
import * as devkitExports from 'nx/src/devkit-exports';
|
import * as devkitExports from 'nx/src/devkit-exports';
|
||||||
@ -96,6 +99,188 @@ describe('application generator', () => {
|
|||||||
expect(tree.exists('test/src/style.none')).toBeFalsy();
|
expect(tree.exists('test/src/style.none')).toBeFalsy();
|
||||||
expect(tree.read('test/src/main.ts', 'utf-8')).not.toContain('styles.none');
|
expect(tree.read('test/src/main.ts', 'utf-8')).not.toContain('styles.none');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await applicationGenerator(tree, {
|
||||||
|
...options,
|
||||||
|
style: 'none',
|
||||||
|
linter: 'eslint',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tree.read('test/vite.config.ts', 'utf-8')).toMatchInlineSnapshot(`
|
||||||
|
"/// <reference types='vitest' />
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import vue from '@vitejs/plugin-vue';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
root: __dirname,
|
||||||
|
cacheDir: '../node_modules/.vite/test',
|
||||||
|
server: {
|
||||||
|
port: 4200,
|
||||||
|
host: 'localhost',
|
||||||
|
},
|
||||||
|
preview: {
|
||||||
|
port: 4300,
|
||||||
|
host: 'localhost',
|
||||||
|
},
|
||||||
|
plugins: [vue()],
|
||||||
|
// Uncomment this if you are using workers.
|
||||||
|
// worker: {
|
||||||
|
// plugins: [ nxViteTsPaths() ],
|
||||||
|
// },
|
||||||
|
build: {
|
||||||
|
outDir: './dist',
|
||||||
|
emptyOutDir: true,
|
||||||
|
reportCompressedSize: true,
|
||||||
|
commonjsOptions: {
|
||||||
|
transformMixedEsModules: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
watch: false,
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||||
|
reporters: ['default'],
|
||||||
|
coverage: {
|
||||||
|
reportsDirectory: './test-output/vitest/coverage',
|
||||||
|
provider: 'v8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./test-e2e",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./test",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'test/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'test/tsconfig.app.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "vue",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "out-tsc/test",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"rootDir": "src",
|
||||||
|
"types": [
|
||||||
|
"vite/client",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.vue",
|
||||||
|
"src/**/*.test.vue",
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"eslint.config.js",
|
||||||
|
"eslint.config.cjs",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.js",
|
||||||
|
"src/**/*.jsx",
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.vue",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'test/tsconfig.spec.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "vue",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "./out-tsc/vitest",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"types": [
|
||||||
|
"vitest/globals",
|
||||||
|
"vitest/importMeta",
|
||||||
|
"vite/client",
|
||||||
|
"node",
|
||||||
|
"vitest",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.app.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
function listFiles(tree: Tree): string[] {
|
function listFiles(tree: Tree): string[] {
|
||||||
|
|||||||
@ -2,14 +2,15 @@ import {
|
|||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
|
joinPathFragments,
|
||||||
readNxJson,
|
readNxJson,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
toJS,
|
toJS,
|
||||||
Tree,
|
Tree,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { Linter } from '@nx/eslint';
|
import { Linter } from '@nx/eslint';
|
||||||
import { initGenerator as jsInitGenerator } from '@nx/js';
|
import { initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { normalizeOptions } from './lib/normalize-options';
|
import { normalizeOptions } from './lib/normalize-options';
|
||||||
import { vueInitGenerator } from '../init/init';
|
import { vueInitGenerator } from '../init/init';
|
||||||
@ -20,6 +21,8 @@ import { addVite } from './lib/add-vite';
|
|||||||
import { extractTsConfigBase } from '../../utils/create-ts-config';
|
import { extractTsConfigBase } from '../../utils/create-ts-config';
|
||||||
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
import { ensureDependencies } from '../../utils/ensure-dependencies';
|
||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export function applicationGenerator(tree: Tree, options: Schema) {
|
export function applicationGenerator(tree: Tree, options: Schema) {
|
||||||
return applicationGeneratorInternal(tree, { addPlugin: false, ...options });
|
return applicationGeneratorInternal(tree, { addPlugin: false, ...options });
|
||||||
@ -29,7 +32,18 @@ export async function applicationGeneratorInternal(
|
|||||||
tree: Tree,
|
tree: Tree,
|
||||||
_options: Schema
|
_options: Schema
|
||||||
): Promise<GeneratorCallback> {
|
): Promise<GeneratorCallback> {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'vue', 'application');
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
tasks.push(
|
||||||
|
await jsInitGenerator(tree, {
|
||||||
|
..._options,
|
||||||
|
tsConfigName: _options.rootProject
|
||||||
|
? 'tsconfig.json'
|
||||||
|
: 'tsconfig.base.json',
|
||||||
|
skipFormat: true,
|
||||||
|
addTsPlugin: _options.useTsSolution,
|
||||||
|
formatter: _options.formatter,
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
const options = await normalizeOptions(tree, _options);
|
const options = await normalizeOptions(tree, _options);
|
||||||
const nxJson = readNxJson(tree);
|
const nxJson = readNxJson(tree);
|
||||||
@ -38,24 +52,28 @@ export async function applicationGeneratorInternal(
|
|||||||
process.env.NX_ADD_PLUGINS !== 'false' &&
|
process.env.NX_ADD_PLUGINS !== 'false' &&
|
||||||
nxJson.useInferencePlugins !== false;
|
nxJson.useInferencePlugins !== false;
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
writeJson(tree, joinPathFragments(options.appProjectRoot, 'package.json'), {
|
||||||
|
name: getImportPath(tree, options.name),
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
nx: {
|
||||||
|
name: options.name,
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: `${options.appProjectRoot}/src`,
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(tree, options.projectName, {
|
addProjectConfiguration(tree, options.projectName, {
|
||||||
root: options.appProjectRoot,
|
root: options.appProjectRoot,
|
||||||
projectType: 'application',
|
projectType: 'application',
|
||||||
sourceRoot: `${options.appProjectRoot}/src`,
|
sourceRoot: `${options.appProjectRoot}/src`,
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
targets: {},
|
targets: {},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(
|
|
||||||
await jsInitGenerator(tree, {
|
|
||||||
...options,
|
|
||||||
tsConfigName: options.rootProject
|
|
||||||
? 'tsconfig.json'
|
|
||||||
: 'tsconfig.base.json',
|
|
||||||
skipFormat: true,
|
|
||||||
})
|
|
||||||
);
|
|
||||||
tasks.push(
|
tasks.push(
|
||||||
await vueInitGenerator(tree, {
|
await vueInitGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
@ -97,6 +115,24 @@ export async function applicationGeneratorInternal(
|
|||||||
|
|
||||||
if (!options.skipFormat) await formatFiles(tree);
|
if (!options.skipFormat) await formatFiles(tree);
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
updateTsconfigFiles(
|
||||||
|
tree,
|
||||||
|
options.appProjectRoot,
|
||||||
|
'tsconfig.app.json',
|
||||||
|
{
|
||||||
|
jsx: 'preserve',
|
||||||
|
jsxImportSource: 'vue',
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
resolveJsonModule: true,
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(() => {
|
tasks.push(() => {
|
||||||
logShowProjectCommand(options.projectName);
|
logShowProjectCommand(options.projectName);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -0,0 +1,5 @@
|
|||||||
|
declare module '*.vue' {
|
||||||
|
import { defineComponent } from 'vue';
|
||||||
|
const component: ReturnType<typeof defineComponent>;
|
||||||
|
export default component;
|
||||||
|
}
|
||||||
@ -4,6 +4,7 @@ import {
|
|||||||
ensureProjectName,
|
ensureProjectName,
|
||||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { NormalizedSchema, Schema } from '../schema';
|
import { NormalizedSchema, Schema } from '../schema';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function normalizeOptions(
|
export async function normalizeOptions(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -39,6 +40,7 @@ export async function normalizeOptions(
|
|||||||
normalized.routing = normalized.routing ?? false;
|
normalized.routing = normalized.routing ?? false;
|
||||||
normalized.unitTestRunner ??= 'vitest';
|
normalized.unitTestRunner ??= 'vitest';
|
||||||
normalized.e2eTestRunner = normalized.e2eTestRunner ?? 'playwright';
|
normalized.e2eTestRunner = normalized.e2eTestRunner ?? 'playwright';
|
||||||
|
normalized.isUsingTsSolutionConfig = isUsingTsSolutionSetup(host);
|
||||||
|
|
||||||
return normalized;
|
return normalized;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,6 +10,7 @@ export interface Schema {
|
|||||||
inSourceTests?: boolean;
|
inSourceTests?: boolean;
|
||||||
e2eTestRunner: 'cypress' | 'playwright' | 'none';
|
e2eTestRunner: 'cypress' | 'playwright' | 'none';
|
||||||
linter: Linter | LinterType;
|
linter: Linter | LinterType;
|
||||||
|
formatter?: 'none' | 'prettier';
|
||||||
routing?: boolean;
|
routing?: boolean;
|
||||||
js?: boolean;
|
js?: boolean;
|
||||||
strict?: boolean;
|
strict?: boolean;
|
||||||
@ -18,6 +19,7 @@ export interface Schema {
|
|||||||
rootProject?: boolean;
|
rootProject?: boolean;
|
||||||
addPlugin?: boolean;
|
addPlugin?: boolean;
|
||||||
nxCloudToken?: string;
|
nxCloudToken?: string;
|
||||||
|
useTsSolution?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NormalizedSchema extends Schema {
|
export interface NormalizedSchema extends Schema {
|
||||||
@ -27,4 +29,5 @@ export interface NormalizedSchema extends Schema {
|
|||||||
e2eProjectRoot: string;
|
e2eProjectRoot: string;
|
||||||
parsedTags: string[];
|
parsedTags: string[];
|
||||||
devServerPort?: number;
|
devServerPort?: number;
|
||||||
|
isUsingTsSolutionConfig: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -60,12 +60,6 @@
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"linter": {
|
|
||||||
"description": "The tool to use for running lint checks.",
|
|
||||||
"type": "string",
|
|
||||||
"enum": ["eslint", "none"],
|
|
||||||
"default": "eslint"
|
|
||||||
},
|
|
||||||
"routing": {
|
"routing": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Generate application with routes.",
|
"description": "Generate application with routes.",
|
||||||
@ -78,12 +72,21 @@
|
|||||||
"default": false,
|
"default": false,
|
||||||
"x-priority": "internal"
|
"x-priority": "internal"
|
||||||
},
|
},
|
||||||
|
"linter": {
|
||||||
|
"description": "The tool to use for running lint checks.",
|
||||||
|
"type": "string",
|
||||||
|
"enum": ["eslint", "none"],
|
||||||
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "none"],
|
"enum": ["vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"x-prompt": "Which unit test runner would you like to use?",
|
"x-prompt": "Which unit test runner would you like to use?",
|
||||||
"default": "vitest"
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -6,7 +6,6 @@ import {
|
|||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
Tree,
|
Tree,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { nxVersion, vueVersion } from '../../utils/versions';
|
import { nxVersion, vueVersion } from '../../utils/versions';
|
||||||
import { InitSchema } from './schema';
|
import { InitSchema } from './schema';
|
||||||
|
|
||||||
@ -28,8 +27,6 @@ function updateDependencies(host: Tree, schema: InitSchema) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function vueInitGenerator(host: Tree, schema: InitSchema) {
|
export async function vueInitGenerator(host: Tree, schema: InitSchema) {
|
||||||
assertNotUsingTsSolutionSetup(host, 'vue', 'init');
|
|
||||||
|
|
||||||
let installTask: GeneratorCallback = () => {};
|
let installTask: GeneratorCallback = () => {};
|
||||||
if (!schema.skipPackageJson) {
|
if (!schema.skipPackageJson) {
|
||||||
installTask = updateDependencies(host, schema);
|
installTask = updateDependencies(host, schema);
|
||||||
|
|||||||
@ -1,12 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "<%= name %>",
|
|
||||||
"version": "0.0.1",
|
|
||||||
"main": "./index.js",
|
|
||||||
"types": "./index.d.ts",
|
|
||||||
"exports": {
|
|
||||||
".": {
|
|
||||||
"import": "./index.mjs",
|
|
||||||
"require": "./index.js"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -31,8 +31,23 @@ export function createLibraryFiles(host: Tree, options: NormalizedSchema) {
|
|||||||
substitutions
|
substitutions
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!options.publishable && options.bundler === 'none') {
|
if (
|
||||||
host.delete(`${options.projectRoot}/package.json`);
|
!options.isUsingTsSolutionConfig &&
|
||||||
|
(options.publishable || options.bundler !== 'none')
|
||||||
|
) {
|
||||||
|
writeJson(host, joinPathFragments(options.projectRoot, 'package.json'), {
|
||||||
|
name: options.name,
|
||||||
|
version: '0.0.1',
|
||||||
|
main: './index.js',
|
||||||
|
types: './index.d.ts',
|
||||||
|
exports: {
|
||||||
|
'.': {
|
||||||
|
import: './index.mjs',
|
||||||
|
require: './index.js',
|
||||||
|
types: './index.d.ts',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.unitTestRunner !== 'vitest') {
|
if (options.unitTestRunner !== 'vitest') {
|
||||||
|
|||||||
@ -10,6 +10,7 @@ import {
|
|||||||
ensureProjectName,
|
ensureProjectName,
|
||||||
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
} from '@nx/devkit/src/generators/project-name-and-root-utils';
|
||||||
import { NormalizedSchema, Schema } from '../schema';
|
import { NormalizedSchema, Schema } from '../schema';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export async function normalizeOptions(
|
export async function normalizeOptions(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
@ -60,6 +61,7 @@ export async function normalizeOptions(
|
|||||||
projectRoot,
|
projectRoot,
|
||||||
parsedTags,
|
parsedTags,
|
||||||
importPath,
|
importPath,
|
||||||
|
isUsingTsSolutionConfig: isUsingTsSolutionSetup(host),
|
||||||
} as NormalizedSchema;
|
} as NormalizedSchema;
|
||||||
|
|
||||||
// Libraries with a bundler or is publishable must also be buildable.
|
// Libraries with a bundler or is publishable must also be buildable.
|
||||||
|
|||||||
@ -5,6 +5,7 @@ import {
|
|||||||
readProjectConfiguration,
|
readProjectConfiguration,
|
||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
|
||||||
import { Linter } from '@nx/eslint';
|
import { Linter } from '@nx/eslint';
|
||||||
@ -438,4 +439,212 @@ module.exports = [
|
|||||||
expect(eslintConfig.overrides[0].files).toContain('*.vue');
|
expect(eslintConfig.overrides[0].files).toContain('*.vue');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
describe('TS solution setup', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
tree = createTreeWithEmptyWorkspace();
|
||||||
|
updateJson(tree, 'package.json', (json) => {
|
||||||
|
json.workspaces = ['packages/*', 'apps/*'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.base.json', {
|
||||||
|
compilerOptions: {
|
||||||
|
composite: true,
|
||||||
|
declaration: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
writeJson(tree, 'tsconfig.json', {
|
||||||
|
extends: './tsconfig.base.json',
|
||||||
|
files: [],
|
||||||
|
references: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should add project references when using TS solution', async () => {
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultSchema,
|
||||||
|
setParserOptionsProject: true,
|
||||||
|
linter: 'eslint',
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(tree.read('my-lib/vite.config.ts', 'utf-8'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
"import vue from '@vitejs/plugin-vue';
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
root: __dirname,
|
||||||
|
cacheDir: '../node_modules/.vite/my-lib',
|
||||||
|
plugins: [vue()],
|
||||||
|
// Uncomment this if you are using workers.
|
||||||
|
// worker: {
|
||||||
|
// plugins: [ nxViteTsPaths() ],
|
||||||
|
// },
|
||||||
|
test: {
|
||||||
|
watch: false,
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||||
|
reporters: ['default'],
|
||||||
|
coverage: {
|
||||||
|
reportsDirectory: './test-output/vitest/coverage',
|
||||||
|
provider: 'v8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
"
|
||||||
|
`);
|
||||||
|
|
||||||
|
expect(readJson(tree, 'tsconfig.json').references).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"path": "./my-lib",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'my-lib/tsconfig.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"files": [],
|
||||||
|
"include": [],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.lib.json",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.spec.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'my-lib/tsconfig.lib.json')).toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "vue",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "out-tsc/my-lib",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"rootDir": "src",
|
||||||
|
"types": [
|
||||||
|
"vite/client",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"exclude": [
|
||||||
|
"dist",
|
||||||
|
"src/**/__tests__/*",
|
||||||
|
"src/**/*.spec.vue",
|
||||||
|
"src/**/*.test.vue",
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"eslint.config.js",
|
||||||
|
"eslint.config.cjs",
|
||||||
|
"eslint.config.mjs",
|
||||||
|
],
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"src/**/*.js",
|
||||||
|
"src/**/*.jsx",
|
||||||
|
"src/**/*.ts",
|
||||||
|
"src/**/*.tsx",
|
||||||
|
"src/**/*.vue",
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
expect(readJson(tree, 'my-lib/tsconfig.spec.json'))
|
||||||
|
.toMatchInlineSnapshot(`
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"jsx": "preserve",
|
||||||
|
"jsxImportSource": "vue",
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"outDir": "./out-tsc/vitest",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"types": [
|
||||||
|
"vitest/globals",
|
||||||
|
"vitest/importMeta",
|
||||||
|
"vite/client",
|
||||||
|
"node",
|
||||||
|
"vitest",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"extends": "../tsconfig.base.json",
|
||||||
|
"include": [
|
||||||
|
"vite.config.ts",
|
||||||
|
"vite.config.mts",
|
||||||
|
"vitest.config.ts",
|
||||||
|
"vitest.config.mts",
|
||||||
|
"src/**/*.test.ts",
|
||||||
|
"src/**/*.spec.ts",
|
||||||
|
"src/**/*.test.tsx",
|
||||||
|
"src/**/*.spec.tsx",
|
||||||
|
"src/**/*.test.js",
|
||||||
|
"src/**/*.spec.js",
|
||||||
|
"src/**/*.test.jsx",
|
||||||
|
"src/**/*.spec.jsx",
|
||||||
|
"src/**/*.d.ts",
|
||||||
|
],
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "./tsconfig.lib.json",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should exclude non-buildable libraries from TS plugin registration', async () => {
|
||||||
|
updateJson(tree, 'nx.json', (json) => {
|
||||||
|
json.plugins = ['@nx/js/typescript'];
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
await libraryGenerator(tree, {
|
||||||
|
...defaultSchema,
|
||||||
|
addPlugin: true,
|
||||||
|
setParserOptionsProject: true,
|
||||||
|
linter: 'eslint',
|
||||||
|
bundler: 'none',
|
||||||
|
});
|
||||||
|
|
||||||
|
const nxJson = readJson(tree, 'nx.json');
|
||||||
|
expect(nxJson.plugins).toMatchInlineSnapshot(`
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"exclude": [
|
||||||
|
"my-lib/*",
|
||||||
|
],
|
||||||
|
"plugin": "@nx/js/typescript",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"targetName": "lint",
|
||||||
|
},
|
||||||
|
"plugin": "@nx/eslint/plugin",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"options": {
|
||||||
|
"buildTargetName": "build",
|
||||||
|
"previewTargetName": "preview",
|
||||||
|
"serveStaticTargetName": "serve-static",
|
||||||
|
"serveTargetName": "serve",
|
||||||
|
"testTargetName": "test",
|
||||||
|
"typecheckTargetName": "typecheck",
|
||||||
|
},
|
||||||
|
"plugin": "@nx/vite/plugin",
|
||||||
|
},
|
||||||
|
]
|
||||||
|
`);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -2,14 +2,17 @@ import {
|
|||||||
addProjectConfiguration,
|
addProjectConfiguration,
|
||||||
formatFiles,
|
formatFiles,
|
||||||
GeneratorCallback,
|
GeneratorCallback,
|
||||||
|
installPackagesTask,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
|
readNxJson,
|
||||||
runTasksInSerial,
|
runTasksInSerial,
|
||||||
toJS,
|
toJS,
|
||||||
Tree,
|
Tree,
|
||||||
updateJson,
|
updateJson,
|
||||||
|
updateNxJson,
|
||||||
|
writeJson,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js';
|
import { addTsConfigPath, initGenerator as jsInitGenerator } from '@nx/js';
|
||||||
import { assertNotUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
|
||||||
import { vueInitGenerator } from '../init/init';
|
import { vueInitGenerator } from '../init/init';
|
||||||
import { Schema } from './schema';
|
import { Schema } from './schema';
|
||||||
import { normalizeOptions } from './lib/normalize-options';
|
import { normalizeOptions } from './lib/normalize-options';
|
||||||
@ -22,16 +25,19 @@ import { ensureDependencies } from '../../utils/ensure-dependencies';
|
|||||||
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
|
||||||
import { getRelativeCwd } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
import { getRelativeCwd } from '@nx/devkit/src/generators/artifact-name-and-directory-utils';
|
||||||
import { relative } from 'path';
|
import { relative } from 'path';
|
||||||
|
import { getImportPath } from '@nx/js/src/utils/get-import-path';
|
||||||
|
import { updateTsconfigFiles } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
import { ensureProjectIsExcludedFromPluginRegistrations } from '@nx/js/src/utils/typescript/plugin';
|
||||||
|
|
||||||
export function libraryGenerator(tree: Tree, schema: Schema) {
|
export function libraryGenerator(tree: Tree, schema: Schema) {
|
||||||
return libraryGeneratorInternal(tree, { addPlugin: false, ...schema });
|
return libraryGeneratorInternal(tree, { addPlugin: false, ...schema });
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
||||||
assertNotUsingTsSolutionSetup(tree, 'vue', 'library');
|
|
||||||
|
|
||||||
const tasks: GeneratorCallback[] = [];
|
const tasks: GeneratorCallback[] = [];
|
||||||
|
|
||||||
|
tasks.push(await jsInitGenerator(tree, { ...schema, skipFormat: true }));
|
||||||
|
|
||||||
const options = await normalizeOptions(tree, schema);
|
const options = await normalizeOptions(tree, schema);
|
||||||
if (options.publishable === true && !schema.importPath) {
|
if (options.publishable === true && !schema.importPath) {
|
||||||
throw new Error(
|
throw new Error(
|
||||||
@ -39,6 +45,34 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
const moduleFile =
|
||||||
|
options.bundler === 'none'
|
||||||
|
? options.js
|
||||||
|
? './src/index.js'
|
||||||
|
: './src/index.ts'
|
||||||
|
: './dist/index.mjs';
|
||||||
|
const typesFile =
|
||||||
|
options.bundler === 'none'
|
||||||
|
? options.js
|
||||||
|
? './src/index.js'
|
||||||
|
: './src/index.ts'
|
||||||
|
: './dist/index.d.ts';
|
||||||
|
writeJson(tree, joinPathFragments(options.projectRoot, 'package.json'), {
|
||||||
|
name: getImportPath(tree, options.name),
|
||||||
|
version: '0.0.1',
|
||||||
|
private: true,
|
||||||
|
module: moduleFile,
|
||||||
|
types: typesFile,
|
||||||
|
files: options.publishable ? ['dist', '!**/*.tsbuildinfo'] : undefined,
|
||||||
|
nx: {
|
||||||
|
name: options.name,
|
||||||
|
projectType: 'application',
|
||||||
|
sourceRoot: `${options.projectRoot}/src`,
|
||||||
|
tags: options.parsedTags?.length ? options.parsedTags : undefined,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
addProjectConfiguration(tree, options.name, {
|
addProjectConfiguration(tree, options.name, {
|
||||||
root: options.projectRoot,
|
root: options.projectRoot,
|
||||||
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
sourceRoot: joinPathFragments(options.projectRoot, 'src'),
|
||||||
@ -46,8 +80,8 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
|||||||
tags: options.parsedTags,
|
tags: options.parsedTags,
|
||||||
targets: {},
|
targets: {},
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(await jsInitGenerator(tree, { ...schema, skipFormat: true }));
|
|
||||||
tasks.push(
|
tasks.push(
|
||||||
await vueInitGenerator(tree, {
|
await vueInitGenerator(tree, {
|
||||||
...options,
|
...options,
|
||||||
@ -86,14 +120,23 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.publishable || options.bundler !== 'none') {
|
if (
|
||||||
|
!options.isUsingTsSolutionConfig &&
|
||||||
|
(options.publishable || options.bundler !== 'none')
|
||||||
|
) {
|
||||||
updateJson(tree, `${options.projectRoot}/package.json`, (json) => {
|
updateJson(tree, `${options.projectRoot}/package.json`, (json) => {
|
||||||
json.name = options.importPath;
|
json.name = options.importPath;
|
||||||
return json;
|
return json;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!options.skipTsConfig) {
|
if (options.bundler === 'none') {
|
||||||
|
const nxJson = readNxJson(tree);
|
||||||
|
ensureProjectIsExcludedFromPluginRegistrations(nxJson, options.projectRoot);
|
||||||
|
updateNxJson(tree, nxJson);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!options.skipTsConfig && !options.isUsingTsSolutionConfig) {
|
||||||
addTsConfigPath(tree, options.importPath, [
|
addTsConfigPath(tree, options.importPath, [
|
||||||
joinPathFragments(
|
joinPathFragments(
|
||||||
options.projectRoot,
|
options.projectRoot,
|
||||||
@ -107,6 +150,29 @@ export async function libraryGeneratorInternal(tree: Tree, schema: Schema) {
|
|||||||
|
|
||||||
if (!options.skipFormat) await formatFiles(tree);
|
if (!options.skipFormat) await formatFiles(tree);
|
||||||
|
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
updateTsconfigFiles(
|
||||||
|
tree,
|
||||||
|
options.projectRoot,
|
||||||
|
'tsconfig.lib.json',
|
||||||
|
{
|
||||||
|
jsx: 'preserve',
|
||||||
|
jsxImportSource: 'vue',
|
||||||
|
module: 'esnext',
|
||||||
|
moduleResolution: 'bundler',
|
||||||
|
resolveJsonModule: true,
|
||||||
|
},
|
||||||
|
options.linter === 'eslint'
|
||||||
|
? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs']
|
||||||
|
: undefined
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always run install to link packages.
|
||||||
|
if (options.isUsingTsSolutionConfig) {
|
||||||
|
tasks.push(() => installPackagesTask(tree, true));
|
||||||
|
}
|
||||||
|
|
||||||
tasks.push(() => {
|
tasks.push(() => {
|
||||||
logShowProjectCommand(options.name);
|
logShowProjectCommand(options.name);
|
||||||
});
|
});
|
||||||
|
|||||||
@ -35,4 +35,5 @@ export interface NormalizedSchema extends Schema {
|
|||||||
appMain?: string;
|
appMain?: string;
|
||||||
appSourceRoot?: string;
|
appSourceRoot?: string;
|
||||||
unitTestRunner?: 'vitest' | 'none';
|
unitTestRunner?: 'vitest' | 'none';
|
||||||
|
isUsingTsSolutionConfig: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,13 +36,17 @@
|
|||||||
"description": "The tool to use for running lint checks.",
|
"description": "The tool to use for running lint checks.",
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["eslint", "none"],
|
"enum": ["eslint", "none"],
|
||||||
"default": "eslint"
|
"default": "none",
|
||||||
|
"x-prompt": "Which linter would you like to use?",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"unitTestRunner": {
|
"unitTestRunner": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": ["vitest", "none"],
|
"enum": ["vitest", "none"],
|
||||||
"description": "Test runner to use for unit tests.",
|
"description": "Test runner to use for unit tests.",
|
||||||
"x-prompt": "What unit test runner should be used?"
|
"x-prompt": "What unit test runner should be used?",
|
||||||
|
"default": "none",
|
||||||
|
"x-priority": "important"
|
||||||
},
|
},
|
||||||
"inSourceTests": {
|
"inSourceTests": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -1,7 +1,80 @@
|
|||||||
import { Tree, updateJson, writeJson } from '@nx/devkit';
|
import { Tree, updateJson, writeJson } from '@nx/devkit';
|
||||||
import * as shared from '@nx/js/src/utils/typescript/create-ts-config';
|
import * as shared from '@nx/js/src/utils/typescript/create-ts-config';
|
||||||
|
import { isUsingTsSolutionSetup } from '@nx/js/src/utils/typescript/ts-solution-setup';
|
||||||
|
|
||||||
export function createTsConfig(
|
export function createTsConfig(
|
||||||
|
host: Tree,
|
||||||
|
projectRoot: string,
|
||||||
|
type: 'app' | 'lib',
|
||||||
|
options: {
|
||||||
|
strict?: boolean;
|
||||||
|
style?: string;
|
||||||
|
bundler?: string;
|
||||||
|
rootProject?: boolean;
|
||||||
|
unitTestRunner?: string;
|
||||||
|
},
|
||||||
|
relativePathToRootTsConfig: string
|
||||||
|
) {
|
||||||
|
if (isUsingTsSolutionSetup(host)) {
|
||||||
|
createTsConfigForTsSolution(
|
||||||
|
host,
|
||||||
|
projectRoot,
|
||||||
|
type,
|
||||||
|
options,
|
||||||
|
relativePathToRootTsConfig
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
createTsConfigForNonTsSolution(
|
||||||
|
host,
|
||||||
|
projectRoot,
|
||||||
|
type,
|
||||||
|
options,
|
||||||
|
relativePathToRootTsConfig
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createTsConfigForTsSolution(
|
||||||
|
host: Tree,
|
||||||
|
projectRoot: string,
|
||||||
|
type: 'app' | 'lib',
|
||||||
|
options: {
|
||||||
|
strict?: boolean;
|
||||||
|
style?: string;
|
||||||
|
rootProject?: boolean;
|
||||||
|
unitTestRunner?: string;
|
||||||
|
},
|
||||||
|
relativePathToRootTsConfig: string
|
||||||
|
) {
|
||||||
|
const json = {
|
||||||
|
extends: relativePathToRootTsConfig,
|
||||||
|
files: [],
|
||||||
|
include: [],
|
||||||
|
references: [
|
||||||
|
{
|
||||||
|
path: type === 'app' ? './tsconfig.app.json' : './tsconfig.lib.json',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
} as any;
|
||||||
|
|
||||||
|
writeJson(host, `${projectRoot}/tsconfig.json`, json);
|
||||||
|
|
||||||
|
const tsconfigProjectPath = `${projectRoot}/tsconfig.${type}.json`;
|
||||||
|
if (host.exists(tsconfigProjectPath)) {
|
||||||
|
updateJson(host, tsconfigProjectPath, (json) => {
|
||||||
|
json.compilerOptions ??= {};
|
||||||
|
|
||||||
|
const types = new Set(json.compilerOptions.types ?? []);
|
||||||
|
types.add('vite/client');
|
||||||
|
|
||||||
|
json.compilerOptions.types = Array.from(types);
|
||||||
|
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createTsConfigForNonTsSolution(
|
||||||
host: Tree,
|
host: Tree,
|
||||||
projectRoot: string,
|
projectRoot: string,
|
||||||
type: 'app' | 'lib',
|
type: 'app' | 'lib',
|
||||||
|
|||||||
@ -421,7 +421,11 @@ function setUpWorkspacesInPackageJson(tree: Tree, options: NormalizedSchema) {
|
|||||||
options.preset === Preset.NextJs ||
|
options.preset === Preset.NextJs ||
|
||||||
options.preset === Preset.ReactMonorepo ||
|
options.preset === Preset.ReactMonorepo ||
|
||||||
options.preset === Preset.ReactNative ||
|
options.preset === Preset.ReactNative ||
|
||||||
options.preset === Preset.RemixMonorepo) &&
|
options.preset === Preset.RemixMonorepo ||
|
||||||
|
options.preset === Preset.VueMonorepo ||
|
||||||
|
options.preset === Preset.Nuxt ||
|
||||||
|
options.preset === Preset.NodeMonorepo ||
|
||||||
|
options.preset === Preset.Express) &&
|
||||||
options.workspaces)
|
options.workspaces)
|
||||||
) {
|
) {
|
||||||
const workspaces = options.workspaceGlobs ?? ['packages/**'];
|
const workspaces = options.workspaceGlobs ?? ['packages/**'];
|
||||||
|
|||||||
@ -135,6 +135,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
e2eTestRunner: options.e2eTestRunner ?? 'playwright',
|
e2eTestRunner: options.e2eTestRunner ?? 'playwright',
|
||||||
addPlugin,
|
addPlugin,
|
||||||
nxCloudToken: options.nxCloudToken,
|
nxCloudToken: options.nxCloudToken,
|
||||||
|
useTsSolution: options.workspaces,
|
||||||
|
formatter: options.formatter,
|
||||||
});
|
});
|
||||||
} else if (options.preset === Preset.VueStandalone) {
|
} else if (options.preset === Preset.VueStandalone) {
|
||||||
const { applicationGenerator: vueApplicationGenerator } = require('@nx' +
|
const { applicationGenerator: vueApplicationGenerator } = require('@nx' +
|
||||||
@ -163,6 +165,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
e2eTestRunner: options.e2eTestRunner ?? 'playwright',
|
e2eTestRunner: options.e2eTestRunner ?? 'playwright',
|
||||||
addPlugin,
|
addPlugin,
|
||||||
nxCloudToken: options.nxCloudToken,
|
nxCloudToken: options.nxCloudToken,
|
||||||
|
useTsSolution: options.workspaces,
|
||||||
|
formatter: options.formatter,
|
||||||
});
|
});
|
||||||
} else if (options.preset === Preset.NuxtStandalone) {
|
} else if (options.preset === Preset.NuxtStandalone) {
|
||||||
const { applicationGenerator: nuxtApplicationGenerator } = require('@nx' +
|
const { applicationGenerator: nuxtApplicationGenerator } = require('@nx' +
|
||||||
@ -234,6 +238,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
e2eTestRunner: options.e2eTestRunner ?? 'jest',
|
e2eTestRunner: options.e2eTestRunner ?? 'jest',
|
||||||
addPlugin,
|
addPlugin,
|
||||||
|
useTsSolution: options.workspaces,
|
||||||
|
formatter: options.formatter,
|
||||||
});
|
});
|
||||||
} else if (options.preset === Preset.Express) {
|
} else if (options.preset === Preset.Express) {
|
||||||
const {
|
const {
|
||||||
@ -245,6 +251,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
linter: options.linter,
|
linter: options.linter,
|
||||||
e2eTestRunner: options.e2eTestRunner ?? 'jest',
|
e2eTestRunner: options.e2eTestRunner ?? 'jest',
|
||||||
addPlugin,
|
addPlugin,
|
||||||
|
useTsSolution: options.workspaces,
|
||||||
|
formatter: options.formatter,
|
||||||
});
|
});
|
||||||
} else if (options.preset === Preset.ReactNative) {
|
} else if (options.preset === Preset.ReactNative) {
|
||||||
const { reactNativeApplicationGenerator } = require('@nx' +
|
const { reactNativeApplicationGenerator } = require('@nx' +
|
||||||
@ -322,6 +330,8 @@ async function createPreset(tree: Tree, options: Schema) {
|
|||||||
rootProject: false,
|
rootProject: false,
|
||||||
e2eTestRunner: options.e2eTestRunner ?? 'jest',
|
e2eTestRunner: options.e2eTestRunner ?? 'jest',
|
||||||
addPlugin,
|
addPlugin,
|
||||||
|
useTsSolution: options.workspaces,
|
||||||
|
formatter: options.formatter,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
throw new Error(`Invalid preset ${options.preset}`);
|
throw new Error(`Invalid preset ${options.preset}`);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user