feat(core): rewrite path mappings when buildings apps
This commit is contained in:
parent
0b7535ae92
commit
2c42431130
@ -64,11 +64,13 @@ The prefix to apply to generated selectors.
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Generate a simple TS library when set to true.
|
Generate a buildable library.
|
||||||
|
|
||||||
### routing
|
### routing
|
||||||
|
|
||||||
|
|||||||
@ -78,9 +78,11 @@ Library name
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Create a publishable library. A "build" architect will be added for this project the workspace configuration.
|
Create a buildable library.
|
||||||
|
|
||||||
### service
|
### service
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,14 @@ Type: `array`
|
|||||||
|
|
||||||
List of static application assets.
|
List of static application assets.
|
||||||
|
|
||||||
|
### buildLibsFromSource
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Read buildable libraries from source instead of building them separately.
|
||||||
|
|
||||||
### externalDependencies
|
### externalDependencies
|
||||||
|
|
||||||
Default: `all`
|
Default: `all`
|
||||||
|
|||||||
@ -62,9 +62,11 @@ Library name
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Create a publishable library. A "build" architect will be added for this project the workspace configuration.
|
Create a publishable library.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
|
|||||||
@ -102,9 +102,11 @@ Use pascal case component file name (e.g. App.tsx)
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Create a publishable library. A "build" architect will be added for this project the workspace configuration.
|
Create a buildable library.
|
||||||
|
|
||||||
### routing
|
### routing
|
||||||
|
|
||||||
|
|||||||
@ -26,6 +26,14 @@ Type: `array`
|
|||||||
|
|
||||||
Budget thresholds to ensure parts of your application stay within boundaries which you set.
|
Budget thresholds to ensure parts of your application stay within boundaries which you set.
|
||||||
|
|
||||||
|
### buildLibsFromSource
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Read buildable libraries from source instead of building them separately.
|
||||||
|
|
||||||
### commonChunk
|
### commonChunk
|
||||||
|
|
||||||
Default: `true`
|
Default: `true`
|
||||||
|
|||||||
@ -64,11 +64,13 @@ The prefix to apply to generated selectors.
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Generate a simple TS library when set to true.
|
Generate a buildable library.
|
||||||
|
|
||||||
### routing
|
### routing
|
||||||
|
|
||||||
|
|||||||
@ -78,9 +78,11 @@ Library name
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Create a publishable library. A "build" architect will be added for this project the workspace configuration.
|
Create a buildable library.
|
||||||
|
|
||||||
### service
|
### service
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,14 @@ Type: `array`
|
|||||||
|
|
||||||
List of static application assets.
|
List of static application assets.
|
||||||
|
|
||||||
|
### buildLibsFromSource
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Read buildable libraries from source instead of building them separately.
|
||||||
|
|
||||||
### externalDependencies
|
### externalDependencies
|
||||||
|
|
||||||
Default: `all`
|
Default: `all`
|
||||||
|
|||||||
@ -62,9 +62,11 @@ Library name
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Create a publishable library. A "build" architect will be added for this project the workspace configuration.
|
Create a publishable library.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
|
|||||||
@ -102,9 +102,11 @@ Use pascal case component file name (e.g. App.tsx)
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Create a publishable library. A "build" architect will be added for this project the workspace configuration.
|
Create a buildable library.
|
||||||
|
|
||||||
### routing
|
### routing
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,14 @@ Type: `array`
|
|||||||
|
|
||||||
Budget thresholds to ensure parts of your application stay within boundaries which you set.
|
Budget thresholds to ensure parts of your application stay within boundaries which you set.
|
||||||
|
|
||||||
|
### buildLibsFromSource
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Read buildable libraries from source instead of building them separately.
|
||||||
|
|
||||||
### commonChunk
|
### commonChunk
|
||||||
|
|
||||||
Default: `true`
|
Default: `true`
|
||||||
|
|||||||
@ -64,11 +64,13 @@ The prefix to apply to generated selectors.
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Default: `false`
|
Default: `false`
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Generate a simple TS library when set to true.
|
Generate a buildable library.
|
||||||
|
|
||||||
### routing
|
### routing
|
||||||
|
|
||||||
|
|||||||
@ -78,9 +78,11 @@ Library name
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Create a publishable library. A "build" architect will be added for this project the workspace configuration.
|
Create a buildable library.
|
||||||
|
|
||||||
### service
|
### service
|
||||||
|
|
||||||
|
|||||||
@ -13,6 +13,14 @@ Type: `array`
|
|||||||
|
|
||||||
List of static application assets.
|
List of static application assets.
|
||||||
|
|
||||||
|
### buildLibsFromSource
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Read buildable libraries from source instead of building them separately.
|
||||||
|
|
||||||
### externalDependencies
|
### externalDependencies
|
||||||
|
|
||||||
Default: `all`
|
Default: `all`
|
||||||
|
|||||||
@ -62,9 +62,11 @@ Library name
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Create a publishable library. A "build" architect will be added for this project the workspace configuration.
|
Create a publishable library.
|
||||||
|
|
||||||
### skipFormat
|
### skipFormat
|
||||||
|
|
||||||
|
|||||||
@ -102,9 +102,11 @@ Use pascal case component file name (e.g. App.tsx)
|
|||||||
|
|
||||||
### publishable
|
### publishable
|
||||||
|
|
||||||
|
Alias(es): buildable
|
||||||
|
|
||||||
Type: `boolean`
|
Type: `boolean`
|
||||||
|
|
||||||
Create a publishable library. A "build" architect will be added for this project the workspace configuration.
|
Create a buildable library.
|
||||||
|
|
||||||
### routing
|
### routing
|
||||||
|
|
||||||
|
|||||||
@ -27,6 +27,14 @@ Type: `array`
|
|||||||
|
|
||||||
Budget thresholds to ensure parts of your application stay within boundaries which you set.
|
Budget thresholds to ensure parts of your application stay within boundaries which you set.
|
||||||
|
|
||||||
|
### buildLibsFromSource
|
||||||
|
|
||||||
|
Default: `false`
|
||||||
|
|
||||||
|
Type: `boolean`
|
||||||
|
|
||||||
|
Read buildable libraries from source instead of building them separately.
|
||||||
|
|
||||||
### commonChunk
|
### commonChunk
|
||||||
|
|
||||||
Default: `true`
|
Default: `true`
|
||||||
|
|||||||
427
e2e/node.test.ts
427
e2e/node.test.ts
@ -19,7 +19,8 @@ import {
|
|||||||
runNgAdd,
|
runNgAdd,
|
||||||
copyMissingPackages,
|
copyMissingPackages,
|
||||||
setMaxWorkers,
|
setMaxWorkers,
|
||||||
newProject
|
newProject,
|
||||||
|
checkFilesDoNotExist
|
||||||
} from './utils';
|
} from './utils';
|
||||||
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
||||||
import { readFile } from './utils';
|
import { readFile } from './utils';
|
||||||
@ -43,6 +44,27 @@ forEachCli(currentCLIName => {
|
|||||||
const linter = currentCLIName === 'angular' ? 'tslint' : 'eslint';
|
const linter = currentCLIName === 'angular' ? 'tslint' : 'eslint';
|
||||||
|
|
||||||
describe('Node Applications', () => {
|
describe('Node Applications', () => {
|
||||||
|
it('should be able to generate an empty application', async () => {
|
||||||
|
ensureProject();
|
||||||
|
const nodeapp = uniq('nodeapp');
|
||||||
|
|
||||||
|
runCLI(`generate @nrwl/node:app ${nodeapp} --linter=${linter}`);
|
||||||
|
|
||||||
|
setMaxWorkers(nodeapp);
|
||||||
|
|
||||||
|
const lintResults = runCLI(`lint ${nodeapp}`);
|
||||||
|
expect(lintResults).toContain('All files pass linting.');
|
||||||
|
|
||||||
|
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
||||||
|
await runCLIAsync(`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!');
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
it('should be able to generate an express application', async done => {
|
it('should be able to generate an express application', async done => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
const nodeapp = uniq('nodeapp');
|
const nodeapp = uniq('nodeapp');
|
||||||
@ -227,95 +249,8 @@ forEachCli(currentCLIName => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}, 120000);
|
}, 120000);
|
||||||
|
|
||||||
describe('nest libraries', function() {
|
|
||||||
it('should be able to generate a nest library', async () => {
|
|
||||||
ensureProject();
|
|
||||||
const nestlib = uniq('nestlib');
|
|
||||||
|
|
||||||
runCLI(`generate @nrwl/nest:lib ${nestlib}`);
|
|
||||||
|
|
||||||
const jestConfigContent = readFile(`libs/${nestlib}/jest.config.js`);
|
|
||||||
|
|
||||||
expect(stripIndents`${jestConfigContent}`).toEqual(
|
|
||||||
stripIndents`module.exports = {
|
|
||||||
name: '${nestlib}',
|
|
||||||
preset: '../../jest.config.js',
|
|
||||||
testEnvironment: 'node',
|
|
||||||
transform: {
|
|
||||||
'^.+\\.[tj]sx?$': 'ts-jest'
|
|
||||||
},
|
|
||||||
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
|
||||||
coverageDirectory: '../../coverage/libs/${nestlib}'
|
|
||||||
};
|
|
||||||
`
|
|
||||||
);
|
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nestlib}`);
|
|
||||||
expect(lintResults).toContain('All files pass linting.');
|
|
||||||
}, 60000);
|
|
||||||
|
|
||||||
it('should be able to generate a nest library w/ service', async () => {
|
|
||||||
ensureProject();
|
|
||||||
const nestlib = uniq('nestlib');
|
|
||||||
|
|
||||||
runCLI(`generate @nrwl/nest:lib ${nestlib} --service`);
|
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nestlib}`);
|
|
||||||
expect(lintResults).toContain('All files pass linting.');
|
|
||||||
|
|
||||||
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
|
||||||
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
|
||||||
}, 60000);
|
|
||||||
|
|
||||||
it('should be able to generate a nest library w/ controller', async () => {
|
|
||||||
ensureProject();
|
|
||||||
const nestlib = uniq('nestlib');
|
|
||||||
|
|
||||||
runCLI(`generate @nrwl/nest:lib ${nestlib} --controller`);
|
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nestlib}`);
|
|
||||||
expect(lintResults).toContain('All files pass linting.');
|
|
||||||
|
|
||||||
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
|
||||||
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
|
||||||
}, 60000);
|
|
||||||
|
|
||||||
it('should be able to generate a nest library w/ controller and service', async () => {
|
|
||||||
ensureProject();
|
|
||||||
const nestlib = uniq('nestlib');
|
|
||||||
|
|
||||||
runCLI(`generate @nrwl/nest:lib ${nestlib} --controller --service`);
|
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nestlib}`);
|
|
||||||
expect(lintResults).toContain('All files pass linting.');
|
|
||||||
|
|
||||||
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
|
||||||
expect(jestResult.stderr).toContain('Test Suites: 2 passed, 2 total');
|
|
||||||
}, 60000);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to generate an empty application', async () => {
|
|
||||||
ensureProject();
|
|
||||||
const nodeapp = uniq('nodeapp');
|
|
||||||
|
|
||||||
runCLI(`generate @nrwl/node:app ${nodeapp} --linter=${linter}`);
|
|
||||||
|
|
||||||
setMaxWorkers(nodeapp);
|
|
||||||
|
|
||||||
const lintResults = runCLI(`lint ${nodeapp}`);
|
|
||||||
expect(lintResults).toContain('All files pass linting.');
|
|
||||||
|
|
||||||
updateFile(`apps/${nodeapp}/src/main.ts`, `console.log('Hello World!');`);
|
|
||||||
await runCLIAsync(`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!');
|
|
||||||
}, 60000);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Node Libraries', () => {
|
describe('Node Libraries', () => {
|
||||||
it('should be able to generate a node library', async () => {
|
it('should be able to generate a node library', async () => {
|
||||||
ensureProject();
|
ensureProject();
|
||||||
@ -390,148 +325,208 @@ forEachCli(currentCLIName => {
|
|||||||
runCLI(`build ${nodelib}`);
|
runCLI(`build ${nodelib}`);
|
||||||
checkFilesExist(`./dist/libs/${nodelib}/esm2015/index.js`);
|
checkFilesExist(`./dist/libs/${nodelib}/esm2015/index.js`);
|
||||||
}, 60000);
|
}, 60000);
|
||||||
|
});
|
||||||
|
|
||||||
describe('with dependencies', () => {
|
describe('nest libraries', function() {
|
||||||
beforeAll(() => {
|
it('should be able to generate a nest library', async () => {
|
||||||
// force a new project to avoid collissions with the npmScope that has been altered before
|
ensureProject();
|
||||||
newProject();
|
const nestlib = uniq('nestlib');
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
runCLI(`generate @nrwl/nest:lib ${nestlib}`);
|
||||||
* Graph:
|
|
||||||
*
|
|
||||||
* childLib
|
|
||||||
* /
|
|
||||||
* parentLib =>
|
|
||||||
* \
|
|
||||||
* \
|
|
||||||
* childLib2
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
let parentLib: string;
|
|
||||||
let childLib: string;
|
|
||||||
let childLib2: string;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
const jestConfigContent = readFile(`libs/${nestlib}/jest.config.js`);
|
||||||
parentLib = uniq('parentlib');
|
|
||||||
childLib = uniq('childlib');
|
|
||||||
childLib2 = uniq('childlib2');
|
|
||||||
|
|
||||||
ensureProject();
|
expect(stripIndents`${jestConfigContent}`).toEqual(
|
||||||
|
stripIndents`module.exports = {
|
||||||
runCLI(`generate @nrwl/node:lib ${parentLib} --publishable=true`);
|
name: '${nestlib}',
|
||||||
runCLI(`generate @nrwl/node:lib ${childLib} --publishable=true`);
|
preset: '../../jest.config.js',
|
||||||
runCLI(`generate @nrwl/node:lib ${childLib2} --publishable=true`);
|
testEnvironment: 'node',
|
||||||
|
transform: {
|
||||||
// create dependencies by importing
|
'^.+\\.[tj]sx?$': 'ts-jest'
|
||||||
const createDep = (parent, children: string[]) => {
|
},
|
||||||
updateFile(
|
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'html'],
|
||||||
`libs/${parent}/src/lib/${parent}.ts`,
|
coverageDirectory: '../../coverage/libs/${nestlib}'
|
||||||
|
};
|
||||||
`
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
const lintResults = runCLI(`lint ${nestlib}`);
|
||||||
|
expect(lintResults).toContain('All files pass linting.');
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
it('should be able to generate a nest library w/ service', async () => {
|
||||||
|
ensureProject();
|
||||||
|
const nestlib = uniq('nestlib');
|
||||||
|
|
||||||
|
runCLI(`generate @nrwl/nest:lib ${nestlib} --service`);
|
||||||
|
|
||||||
|
const lintResults = runCLI(`lint ${nestlib}`);
|
||||||
|
expect(lintResults).toContain('All files pass linting.');
|
||||||
|
|
||||||
|
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
||||||
|
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
it('should be able to generate a nest library w/ controller', async () => {
|
||||||
|
ensureProject();
|
||||||
|
const nestlib = uniq('nestlib');
|
||||||
|
|
||||||
|
runCLI(`generate @nrwl/nest:lib ${nestlib} --controller`);
|
||||||
|
|
||||||
|
const lintResults = runCLI(`lint ${nestlib}`);
|
||||||
|
expect(lintResults).toContain('All files pass linting.');
|
||||||
|
|
||||||
|
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
||||||
|
expect(jestResult.stderr).toContain('Test Suites: 1 passed, 1 total');
|
||||||
|
}, 60000);
|
||||||
|
|
||||||
|
it('should be able to generate a nest library w/ controller and service', async () => {
|
||||||
|
ensureProject();
|
||||||
|
const nestlib = uniq('nestlib');
|
||||||
|
|
||||||
|
runCLI(`generate @nrwl/nest:lib ${nestlib} --controller --service`);
|
||||||
|
|
||||||
|
const lintResults = runCLI(`lint ${nestlib}`);
|
||||||
|
expect(lintResults).toContain('All files pass linting.');
|
||||||
|
|
||||||
|
const jestResult = await runCLIAsync(`test ${nestlib}`);
|
||||||
|
expect(jestResult.stderr).toContain('Test Suites: 2 passed, 2 total');
|
||||||
|
}, 60000);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('with dependencies', () => {
|
||||||
|
/**
|
||||||
|
* Graph:
|
||||||
|
*
|
||||||
|
* childLib
|
||||||
|
* /
|
||||||
|
* app => parentLib =>
|
||||||
|
* \
|
||||||
|
* \
|
||||||
|
* childLib2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
let app: string;
|
||||||
|
let parentLib: string;
|
||||||
|
let childLib: string;
|
||||||
|
let childLib2: string;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
app = uniq('app');
|
||||||
|
parentLib = uniq('parentlib');
|
||||||
|
childLib = uniq('childlib');
|
||||||
|
childLib2 = uniq('childlib2');
|
||||||
|
|
||||||
|
ensureProject();
|
||||||
|
|
||||||
|
runCLI(`generate @nrwl/express:app ${app}`);
|
||||||
|
setMaxWorkers(app);
|
||||||
|
|
||||||
|
runCLI(`generate @nrwl/node:lib ${parentLib} --publishable=true`);
|
||||||
|
runCLI(`generate @nrwl/node:lib ${childLib} --publishable=true`);
|
||||||
|
runCLI(`generate @nrwl/node:lib ${childLib2} --publishable=true`);
|
||||||
|
|
||||||
|
// create dependencies by importing
|
||||||
|
const createDep = (parent, children: string[]) => {
|
||||||
|
updateFile(
|
||||||
|
`libs/${parent}/src/lib/${parent}.ts`,
|
||||||
|
`
|
||||||
${children
|
${children
|
||||||
.map(entry => `import { ${entry} } from '@proj/${entry}';`)
|
.map(entry => `import { ${entry} } from '@proj/${entry}';`)
|
||||||
.join('\n')}
|
.join('\n')}
|
||||||
|
|
||||||
export function ${parent}(): string {
|
export function ${parent}(): string {
|
||||||
return '${parent}' + ' ' + ${children
|
return '${parent}' + ' ' + ${children
|
||||||
.map(entry => `${entry}()`)
|
.map(entry => `${entry}()`)
|
||||||
.join('+')}
|
.join('+')}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
createDep(parentLib, [childLib, childLib2]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should throw an error if the dependent library has not been built before building the parent lib', () => {
|
|
||||||
expect.assertions(2);
|
|
||||||
|
|
||||||
try {
|
|
||||||
runCLI(`build ${parentLib}`);
|
|
||||||
} catch (e) {
|
|
||||||
expect(e.stderr.toString()).toContain(
|
|
||||||
`Some of the project ${parentLib}'s dependencies have not been built yet. Please build these libraries before:`
|
|
||||||
);
|
|
||||||
expect(e.stderr.toString()).toContain(`${childLib}`);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should build a library without dependencies', () => {
|
|
||||||
const childLibOutput = runCLI(`build ${childLib}`);
|
|
||||||
|
|
||||||
expect(childLibOutput).toContain(
|
|
||||||
`Done compiling TypeScript files for library ${childLib}`
|
|
||||||
);
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
createDep(parentLib, [childLib, childLib2]);
|
||||||
|
|
||||||
|
updateFile(
|
||||||
|
`apps/${app}/src/main.ts`,
|
||||||
|
`
|
||||||
|
import "@proj/${parentLib}";
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
// we are setting paths to {} to make sure built libs are read from dist
|
||||||
|
updateFile('tsconfig.json', c => {
|
||||||
|
const json = JSON.parse(c);
|
||||||
|
json.compilerOptions.paths = {};
|
||||||
|
return JSON.stringify(json, null, 2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should build a parent library if the dependent libraries have been built before', () => {
|
|
||||||
const childLibOutput = runCLI(`build ${childLib}`);
|
|
||||||
expect(childLibOutput).toContain(
|
|
||||||
`Done compiling TypeScript files for library ${childLib}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const childLib2Output = runCLI(`build ${childLib2}`);
|
|
||||||
expect(childLib2Output).toContain(
|
|
||||||
`Done compiling TypeScript files for library ${childLib2}`
|
|
||||||
);
|
|
||||||
|
|
||||||
const parentLibOutput = runCLI(`build ${parentLib}`);
|
|
||||||
expect(parentLibOutput).toContain(
|
|
||||||
`Done compiling TypeScript files for library ${parentLib}`
|
|
||||||
);
|
|
||||||
|
|
||||||
// assert package.json deps have been set
|
|
||||||
const assertPackageJson = (
|
|
||||||
parent: string,
|
|
||||||
lib: string,
|
|
||||||
version: string
|
|
||||||
) => {
|
|
||||||
const jsonFile = readJson(`dist/libs/${parent}/package.json`);
|
|
||||||
const childDependencyVersion = jsonFile.dependencies[`@proj/${lib}`];
|
|
||||||
expect(childDependencyVersion).toBe(version);
|
|
||||||
};
|
|
||||||
|
|
||||||
assertPackageJson(parentLib, childLib, '0.0.1');
|
|
||||||
assertPackageJson(parentLib, childLib2, '0.0.1');
|
|
||||||
});
|
|
||||||
|
|
||||||
// it('should automatically build all deps and update package.json when passing --withDeps flags', () => {
|
|
||||||
// const parentLibOutput = runCLI(`build ${parentLib} --withDeps`);
|
|
||||||
|
|
||||||
// expect(parentLibOutput).toContain(
|
|
||||||
// `Done compiling TypeScript files for library ${parentLib}`
|
|
||||||
// );
|
|
||||||
// expect(parentLibOutput).toContain(
|
|
||||||
// `Done compiling TypeScript files for library ${childLib}`
|
|
||||||
// );
|
|
||||||
// expect(parentLibOutput).toContain(
|
|
||||||
// `Done compiling TypeScript files for library ${childChildLib}`
|
|
||||||
// );
|
|
||||||
// expect(parentLibOutput).toContain(
|
|
||||||
// `Done compiling TypeScript files for library ${childLib2}`
|
|
||||||
// );
|
|
||||||
// expect(parentLibOutput).toContain(
|
|
||||||
// `Done compiling TypeScript files for library ${childLibShared}`
|
|
||||||
// );
|
|
||||||
|
|
||||||
// // // assert package.json deps have been set
|
|
||||||
// const assertPackageJson = (
|
|
||||||
// parent: string,
|
|
||||||
// lib: string,
|
|
||||||
// version: string
|
|
||||||
// ) => {
|
|
||||||
// const jsonFile = readJson(`dist/libs/${parent}/package.json`);
|
|
||||||
// const childDependencyVersion =
|
|
||||||
// jsonFile.dependencies[`@proj/${lib}`];
|
|
||||||
// expect(childDependencyVersion).toBe(version);
|
|
||||||
// };
|
|
||||||
|
|
||||||
// assertPackageJson(parentLib, childLib, '0.0.1');
|
|
||||||
// assertPackageJson(childLib, childChildLib, '0.0.1');
|
|
||||||
// assertPackageJson(childLib, childLibShared, '0.0.1');
|
|
||||||
// assertPackageJson(childLib2, childLibShared, '0.0.1');
|
|
||||||
// });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw an error if the dependent library has not been built before building the parent lib', () => {
|
||||||
|
expect.assertions(2);
|
||||||
|
|
||||||
|
try {
|
||||||
|
runCLI(`build ${parentLib}`);
|
||||||
|
} catch (e) {
|
||||||
|
expect(e.stderr.toString()).toContain(
|
||||||
|
`Some of the project ${parentLib}'s dependencies have not been built yet. Please build these libraries before:`
|
||||||
|
);
|
||||||
|
expect(e.stderr.toString()).toContain(`${childLib}`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should build a library without dependencies', () => {
|
||||||
|
const childLibOutput = runCLI(`build ${childLib}`);
|
||||||
|
|
||||||
|
expect(childLibOutput).toContain(
|
||||||
|
`Done compiling TypeScript files for library ${childLib}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should build a parent library if the dependent libraries have been built before', () => {
|
||||||
|
const childLibOutput = runCLI(`build ${childLib}`);
|
||||||
|
expect(childLibOutput).toContain(
|
||||||
|
`Done compiling TypeScript files for library ${childLib}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const childLib2Output = runCLI(`build ${childLib2}`);
|
||||||
|
expect(childLib2Output).toContain(
|
||||||
|
`Done compiling TypeScript files for library ${childLib2}`
|
||||||
|
);
|
||||||
|
|
||||||
|
const parentLibOutput = runCLI(`build ${parentLib}`);
|
||||||
|
expect(parentLibOutput).toContain(
|
||||||
|
`Done compiling TypeScript files for library ${parentLib}`
|
||||||
|
);
|
||||||
|
|
||||||
|
// assert package.json deps have been set
|
||||||
|
const assertPackageJson = (
|
||||||
|
parent: string,
|
||||||
|
lib: string,
|
||||||
|
version: string
|
||||||
|
) => {
|
||||||
|
const jsonFile = readJson(`dist/libs/${parent}/package.json`);
|
||||||
|
const childDependencyVersion = jsonFile.dependencies[`@proj/${lib}`];
|
||||||
|
expect(childDependencyVersion).toBe(version);
|
||||||
|
};
|
||||||
|
|
||||||
|
assertPackageJson(parentLib, childLib, '0.0.1');
|
||||||
|
assertPackageJson(parentLib, childLib2, '0.0.1');
|
||||||
|
});
|
||||||
|
|
||||||
|
if (currentCLIName === 'nx') {
|
||||||
|
it('should build an app composed out of buildable libs', () => {
|
||||||
|
const buildWithDeps = runCLI(`build ${app} --with-deps`);
|
||||||
|
expect(buildWithDeps).toContain(`Running target "build" succeeded`);
|
||||||
|
checkFilesDoNotExist(`apps/${app}/tsconfig/tsconfig.nx-tmp`);
|
||||||
|
|
||||||
|
// we remove all path mappings from the root tsconfig, so when trying to build
|
||||||
|
// libs from source, the builder will throw
|
||||||
|
const failedBuild = runCLI(
|
||||||
|
`build ${app} --with-deps --buildLibsFromSource`,
|
||||||
|
{ silenceError: true }
|
||||||
|
);
|
||||||
|
expect(failedBuild).toContain(`Can't resolve`);
|
||||||
|
}, 1000000);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,44 +1,50 @@
|
|||||||
import {
|
import {
|
||||||
|
checkFilesDoNotExist,
|
||||||
ensureProject,
|
ensureProject,
|
||||||
forEachCli,
|
forEachCli,
|
||||||
readJson,
|
readJson,
|
||||||
runCLI,
|
runCLI,
|
||||||
|
setMaxWorkers,
|
||||||
uniq,
|
uniq,
|
||||||
updateFile
|
updateFile
|
||||||
} from './utils';
|
} from './utils';
|
||||||
|
|
||||||
forEachCli('nx', cli => {
|
forEachCli('nx', cli => {
|
||||||
describe('Build React library', () => {
|
describe('Build React libraries and apps', () => {
|
||||||
/**
|
/**
|
||||||
* Graph:
|
* Graph:
|
||||||
*
|
*
|
||||||
* childLib
|
* childLib
|
||||||
* /
|
* /
|
||||||
* parentLib =>
|
* app => parentLib =>
|
||||||
* \
|
* \
|
||||||
* \
|
* childLib2
|
||||||
* childLib2
|
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
let app: string;
|
||||||
let parentLib: string;
|
let parentLib: string;
|
||||||
let childLib: string;
|
let childLib: string;
|
||||||
let childLib2: string;
|
let childLib2: string;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
|
app = uniq('app');
|
||||||
parentLib = uniq('parentlib');
|
parentLib = uniq('parentlib');
|
||||||
childLib = uniq('childlib');
|
childLib = uniq('childlib');
|
||||||
childLib2 = uniq('childlib2');
|
childLib2 = uniq('childlib2');
|
||||||
|
|
||||||
ensureProject();
|
ensureProject();
|
||||||
|
|
||||||
|
runCLI(`generate @nrwl/react:app ${app}`);
|
||||||
|
setMaxWorkers(app);
|
||||||
|
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/react:library ${parentLib} --publishable=true --no-interactive`
|
`generate @nrwl/react:library ${parentLib} --buildable --no-interactive`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/react:library ${childLib} --publishable=true --no-interactive`
|
`generate @nrwl/react:library ${childLib} --buildable --no-interactive`
|
||||||
);
|
);
|
||||||
runCLI(
|
runCLI(
|
||||||
`generate @nrwl/react:library ${childLib2} --publishable=true --no-interactive`
|
`generate @nrwl/react:library ${childLib2} --buildable --no-interactive`
|
||||||
);
|
);
|
||||||
|
|
||||||
// create dependencies by importing
|
// create dependencies by importing
|
||||||
@ -53,6 +59,20 @@ forEachCli('nx', cli => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
createDep(parentLib, [childLib, childLib2]);
|
createDep(parentLib, [childLib, childLib2]);
|
||||||
|
|
||||||
|
updateFile(
|
||||||
|
`apps/${app}/src/main.tsx`,
|
||||||
|
`
|
||||||
|
import "@proj/${parentLib}";
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
// we are setting paths to {} to make sure built libs are read from dist
|
||||||
|
updateFile('tsconfig.json', c => {
|
||||||
|
const json = JSON.parse(c);
|
||||||
|
json.compilerOptions.paths = {};
|
||||||
|
return JSON.stringify(json, null, 2);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an error if the dependent library has not been built before building the parent lib', () => {
|
it('should throw an error if the dependent library has not been built before building the parent lib', () => {
|
||||||
@ -70,11 +90,11 @@ forEachCli('nx', cli => {
|
|||||||
|
|
||||||
it('should build the library when it does not have any deps', () => {
|
it('should build the library when it does not have any deps', () => {
|
||||||
const output = runCLI(`build ${childLib}`);
|
const output = runCLI(`build ${childLib}`);
|
||||||
expect(output).toContain(`${childLib}.esm5.js`);
|
expect(output).toContain(`${childLib}.esm.js`);
|
||||||
expect(output).toContain(`Bundle complete`);
|
expect(output).toContain(`Bundle complete`);
|
||||||
});
|
});
|
||||||
|
|
||||||
fit('should properly add references to any dependency into the parent package.json', () => {
|
it('should properly add references to any dependency into the parent package.json', () => {
|
||||||
const childLibOutput = runCLI(`build ${childLib}`);
|
const childLibOutput = runCLI(`build ${childLib}`);
|
||||||
const childLib2Output = runCLI(`build ${childLib2}`);
|
const childLib2Output = runCLI(`build ${childLib2}`);
|
||||||
const parentLibOutput = runCLI(`build ${parentLib}`);
|
const parentLibOutput = runCLI(`build ${parentLib}`);
|
||||||
@ -97,6 +117,20 @@ forEachCli('nx', cli => {
|
|||||||
[`@proj/${childLib2}`]: '0.0.1'
|
[`@proj/${childLib2}`]: '0.0.1'
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should build an app composed out of buildable libs', () => {
|
||||||
|
const buildWithDeps = runCLI(`build ${app} --with-deps`);
|
||||||
|
expect(buildWithDeps).toContain(`Running target "build" succeeded`);
|
||||||
|
checkFilesDoNotExist(`apps/${app}/tsconfig/tsconfig.nx-tmp`);
|
||||||
|
|
||||||
|
// we remove all path mappings from the root tsconfig, so when trying to build
|
||||||
|
// libs from source, the builder will throw
|
||||||
|
const failedBuild = runCLI(
|
||||||
|
`build ${app} --with-deps --buildLibsFromSource`,
|
||||||
|
{ silenceError: true }
|
||||||
|
);
|
||||||
|
expect(failedBuild).toContain(`Can't resolve`);
|
||||||
|
}, 1000000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -14,7 +14,7 @@ import {
|
|||||||
DependentBuildableProjectNode,
|
DependentBuildableProjectNode,
|
||||||
updateBuildableProjectPackageJsonDependencies,
|
updateBuildableProjectPackageJsonDependencies,
|
||||||
updatePaths
|
updatePaths
|
||||||
} from '@nrwl/workspace/src/utils/buildale-libs-utils';
|
} from '@nrwl/workspace/src/utils/buildable-libs-utils';
|
||||||
import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph';
|
import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph';
|
||||||
|
|
||||||
export interface BuildAngularLibraryBuilderOptions {
|
export interface BuildAngularLibraryBuilderOptions {
|
||||||
|
|||||||
@ -20,7 +20,8 @@
|
|||||||
"publishable": {
|
"publishable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"default": false,
|
"default": false,
|
||||||
"description": "Generate a simple TS library when set to true."
|
"description": "Generate a buildable library.",
|
||||||
|
"alias": "buildable"
|
||||||
},
|
},
|
||||||
"prefix": {
|
"prefix": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -53,7 +53,8 @@
|
|||||||
},
|
},
|
||||||
"publishable": {
|
"publishable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Create a publishable library. A \"build\" architect will be added for this project the workspace configuration."
|
"description": "Create a buildable library.",
|
||||||
|
"alias": "buildable"
|
||||||
},
|
},
|
||||||
"global": {
|
"global": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -1,3 +1,9 @@
|
|||||||
{
|
{
|
||||||
"schematics": {}
|
"schematics": {
|
||||||
|
"set-build-libs-from-source": {
|
||||||
|
"version": "9.2.0-beta.1",
|
||||||
|
"description": "Set buildLibsFromSource property to true to not break existing projects.",
|
||||||
|
"factory": "./src/migrations/update-9-2-0/set-build-libs-from-source"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,122 +0,0 @@
|
|||||||
import { normalize, JsonObject, workspaces } from '@angular-devkit/core';
|
|
||||||
import { join } from 'path';
|
|
||||||
jest.mock('tsconfig-paths-webpack-plugin');
|
|
||||||
import TsConfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
|
|
||||||
import { BuildNodeBuilderOptions } from './build.impl';
|
|
||||||
import { of } from 'rxjs';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as buildWebpack from '@angular-devkit/build-webpack';
|
|
||||||
import { Architect } from '@angular-devkit/architect';
|
|
||||||
import { getTestArchitect } from '../../utils/testing';
|
|
||||||
|
|
||||||
describe('NodeBuildBuilder', () => {
|
|
||||||
let testOptions: BuildNodeBuilderOptions & JsonObject;
|
|
||||||
let architect: Architect;
|
|
||||||
let runWebpack: jest.Mock;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
[architect] = await getTestArchitect();
|
|
||||||
|
|
||||||
testOptions = {
|
|
||||||
main: 'apps/nodeapp/src/main.ts',
|
|
||||||
tsConfig: 'apps/nodeapp/tsconfig.app.json',
|
|
||||||
outputPath: 'dist/apps/nodeapp',
|
|
||||||
externalDependencies: 'all',
|
|
||||||
fileReplacements: [
|
|
||||||
{
|
|
||||||
replace: 'apps/environment/environment.ts',
|
|
||||||
with: 'apps/environment/environment.prod.ts'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
replace: 'module1.ts',
|
|
||||||
with: 'module2.ts'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
assets: [],
|
|
||||||
statsJson: false
|
|
||||||
};
|
|
||||||
runWebpack = jest.fn().mockImplementation((config, context, options) => {
|
|
||||||
options.logging({
|
|
||||||
toJson: () => ({
|
|
||||||
stats: 'stats'
|
|
||||||
})
|
|
||||||
});
|
|
||||||
return of({ success: true });
|
|
||||||
});
|
|
||||||
(buildWebpack as any).runWebpack = runWebpack;
|
|
||||||
spyOn(workspaces, 'readWorkspace').and.returnValue({
|
|
||||||
workspace: {
|
|
||||||
projects: {
|
|
||||||
get: () => ({
|
|
||||||
sourceRoot: '/root/apps/nodeapp/src'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
(<any>TsConfigPathsPlugin).mockImplementation(
|
|
||||||
function MockPathsPlugin() {}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('run', () => {
|
|
||||||
it('should call runWebpack', async () => {
|
|
||||||
const run = await architect.scheduleBuilder(
|
|
||||||
'@nrwl/node:build',
|
|
||||||
testOptions
|
|
||||||
);
|
|
||||||
await run.output.toPromise();
|
|
||||||
|
|
||||||
await run.stop();
|
|
||||||
|
|
||||||
expect(runWebpack).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should emit the outfile along with success', async () => {
|
|
||||||
const run = await architect.scheduleBuilder(
|
|
||||||
'@nrwl/node:build',
|
|
||||||
testOptions
|
|
||||||
);
|
|
||||||
const output = await run.output.toPromise();
|
|
||||||
|
|
||||||
await run.stop();
|
|
||||||
|
|
||||||
expect(output.success).toEqual(true);
|
|
||||||
expect(output.outfile).toEqual('/root/dist/apps/nodeapp/main.js');
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('webpackConfig option', () => {
|
|
||||||
it('should require the specified function and use the return value', async () => {
|
|
||||||
const mockFunction = jest.fn(config => ({
|
|
||||||
config: 'config'
|
|
||||||
}));
|
|
||||||
jest.mock(
|
|
||||||
join(normalize('/root'), 'apps/nodeapp/webpack.config.js'),
|
|
||||||
() => mockFunction,
|
|
||||||
{
|
|
||||||
virtual: true
|
|
||||||
}
|
|
||||||
);
|
|
||||||
testOptions.webpackConfig = 'apps/nodeapp/webpack.config.js';
|
|
||||||
const run = await architect.scheduleBuilder(
|
|
||||||
'@nrwl/node:build',
|
|
||||||
testOptions
|
|
||||||
);
|
|
||||||
await run.output.toPromise();
|
|
||||||
|
|
||||||
await run.stop();
|
|
||||||
|
|
||||||
expect(mockFunction).toHaveBeenCalled();
|
|
||||||
expect(runWebpack).toHaveBeenCalledWith(
|
|
||||||
{
|
|
||||||
config: 'config'
|
|
||||||
},
|
|
||||||
jasmine.anything(),
|
|
||||||
jasmine.anything()
|
|
||||||
);
|
|
||||||
// expect(runWebpack.calls.first().args[0]).toEqual({
|
|
||||||
// config: 'config'
|
|
||||||
// });
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -10,6 +10,11 @@ import { OUT_FILENAME } from '../../utils/config';
|
|||||||
import { BuildBuilderOptions } from '../../utils/types';
|
import { BuildBuilderOptions } from '../../utils/types';
|
||||||
import { normalizeBuildOptions } from '../../utils/normalize';
|
import { normalizeBuildOptions } from '../../utils/normalize';
|
||||||
import { NodeJsSyncHost } from '@angular-devkit/core/node';
|
import { NodeJsSyncHost } from '@angular-devkit/core/node';
|
||||||
|
import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph';
|
||||||
|
import {
|
||||||
|
calculateProjectDependencies,
|
||||||
|
createTmpTsConfig
|
||||||
|
} from '@nrwl/workspace/src/utils/buildable-libs-utils';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
require('dotenv').config();
|
require('dotenv').config();
|
||||||
@ -19,6 +24,7 @@ export interface BuildNodeBuilderOptions extends BuildBuilderOptions {
|
|||||||
optimization?: boolean;
|
optimization?: boolean;
|
||||||
sourceMap?: boolean;
|
sourceMap?: boolean;
|
||||||
externalDependencies: 'all' | 'none' | string[];
|
externalDependencies: 'all' | 'none' | string[];
|
||||||
|
buildLibsFromSource?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type NodeBuildEvent = BuildResult & {
|
export type NodeBuildEvent = BuildResult & {
|
||||||
@ -31,6 +37,20 @@ function run(
|
|||||||
options: JsonObject & BuildNodeBuilderOptions,
|
options: JsonObject & BuildNodeBuilderOptions,
|
||||||
context: BuilderContext
|
context: BuilderContext
|
||||||
): Observable<NodeBuildEvent> {
|
): Observable<NodeBuildEvent> {
|
||||||
|
if (!options.buildLibsFromSource) {
|
||||||
|
const projGraph = createProjectGraph();
|
||||||
|
const { target, dependencies } = calculateProjectDependencies(
|
||||||
|
projGraph,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
options.tsConfig = createTmpTsConfig(
|
||||||
|
options.tsConfig,
|
||||||
|
context.workspaceRoot,
|
||||||
|
target.data.root,
|
||||||
|
dependencies
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return from(getSourceRoot(context)).pipe(
|
return from(getSourceRoot(context)).pipe(
|
||||||
map(sourceRoot =>
|
map(sourceRoot =>
|
||||||
normalizeBuildOptions(options, context.workspaceRoot, sourceRoot)
|
normalizeBuildOptions(options, context.workspaceRoot, sourceRoot)
|
||||||
|
|||||||
@ -108,6 +108,11 @@
|
|||||||
"webpackConfig": {
|
"webpackConfig": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path to a function which takes a webpack config, context and returns the resulting webpack config"
|
"description": "Path to a function which takes a webpack config, context and returns the resulting webpack config"
|
||||||
|
},
|
||||||
|
"buildLibsFromSource": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Read buildable libraries from source instead of building them separately.",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["tsConfig", "main"],
|
"required": ["tsConfig", "main"],
|
||||||
|
|||||||
@ -1,18 +1,19 @@
|
|||||||
import { Architect } from '@angular-devkit/architect';
|
|
||||||
import { EventEmitter } from 'events';
|
import { EventEmitter } from 'events';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
import { getMockContext, getTestArchitect } from '../../utils/testing';
|
import { getMockContext } from '../../utils/testing';
|
||||||
import { MockBuilderContext } from '@nrwl/workspace/testing';
|
import { MockBuilderContext } from '@nrwl/workspace/testing';
|
||||||
|
import * as projectGraphUtils from '@nrwl/workspace/src/core/project-graph';
|
||||||
import {
|
import {
|
||||||
ProjectGraph,
|
ProjectGraph,
|
||||||
ProjectType
|
ProjectType
|
||||||
} from '@nrwl/workspace/src/core/project-graph';
|
} from '@nrwl/workspace/src/core/project-graph';
|
||||||
import * as projectGraphUtils from '@nrwl/workspace/src/core/project-graph';
|
|
||||||
|
|
||||||
import {
|
import {
|
||||||
NodePackageBuilderOptions,
|
NodePackageBuilderOptions,
|
||||||
runNodePackageBuilder
|
runNodePackageBuilder
|
||||||
} from './package.impl';
|
} from './package.impl';
|
||||||
|
import * as fsMock from 'fs';
|
||||||
|
|
||||||
jest.mock('glob');
|
jest.mock('glob');
|
||||||
let glob = require('glob');
|
let glob = require('glob');
|
||||||
jest.mock('fs-extra');
|
jest.mock('fs-extra');
|
||||||
@ -23,7 +24,6 @@ jest.mock('child_process');
|
|||||||
let { fork } = require('child_process');
|
let { fork } = require('child_process');
|
||||||
jest.mock('tree-kill');
|
jest.mock('tree-kill');
|
||||||
let treeKill = require('tree-kill');
|
let treeKill = require('tree-kill');
|
||||||
import * as fsMock from 'fs';
|
|
||||||
|
|
||||||
describe('NodeCompileBuilder', () => {
|
describe('NodeCompileBuilder', () => {
|
||||||
let testOptions: NodePackageBuilderOptions;
|
let testOptions: NodePackageBuilderOptions;
|
||||||
@ -284,11 +284,7 @@ describe('NodeCompileBuilder', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should call the tsc compiler with the modified tsconfig.json', done => {
|
it('should call the tsc compiler with the modified tsconfig.json', done => {
|
||||||
let tmpTsConfigPath = join(
|
let tmpTsConfigPath = join('libs/nodelib', 'tsconfig.nx-tmp');
|
||||||
context.workspaceRoot,
|
|
||||||
'libs/nodelib',
|
|
||||||
'tsconfig.lib.nx-tmp'
|
|
||||||
);
|
|
||||||
|
|
||||||
runNodePackageBuilder(testOptions, context).subscribe({
|
runNodePackageBuilder(testOptions, context).subscribe({
|
||||||
complete: () => {
|
complete: () => {
|
||||||
@ -308,9 +304,6 @@ describe('NodeCompileBuilder', () => {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
fakeEventEmitter.emit('exit', 0);
|
fakeEventEmitter.emit('exit', 0);
|
||||||
|
|
||||||
// assert temp tsconfig file gets deleted again
|
|
||||||
expect(fsMock.unlinkSync).toHaveBeenCalledWith(tmpTsConfigPath);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -11,21 +11,19 @@ import { copy, removeSync } from 'fs-extra';
|
|||||||
import * as glob from 'glob';
|
import * as glob from 'glob';
|
||||||
import { basename, dirname, join, normalize, relative } from 'path';
|
import { basename, dirname, join, normalize, relative } from 'path';
|
||||||
import { Observable, of, Subscriber } from 'rxjs';
|
import { Observable, of, Subscriber } from 'rxjs';
|
||||||
import { finalize, map, switchMap, tap } from 'rxjs/operators';
|
import { map, switchMap, tap } from 'rxjs/operators';
|
||||||
import * as treeKill from 'tree-kill';
|
import * as treeKill from 'tree-kill';
|
||||||
import {
|
import {
|
||||||
createProjectGraph,
|
createProjectGraph,
|
||||||
ProjectGraph
|
ProjectGraph
|
||||||
} from '@nrwl/workspace/src/core/project-graph';
|
} from '@nrwl/workspace/src/core/project-graph';
|
||||||
import * as ts from 'typescript';
|
|
||||||
import { unlinkSync } from 'fs';
|
|
||||||
import {
|
import {
|
||||||
calculateProjectDependencies,
|
calculateProjectDependencies,
|
||||||
checkDependentProjectsHaveBeenBuilt,
|
checkDependentProjectsHaveBeenBuilt,
|
||||||
|
createTmpTsConfig,
|
||||||
DependentBuildableProjectNode,
|
DependentBuildableProjectNode,
|
||||||
updateBuildableProjectPackageJsonDependencies,
|
updateBuildableProjectPackageJsonDependencies
|
||||||
updatePaths
|
} from '@nrwl/workspace/src/utils/buildable-libs-utils';
|
||||||
} from '@nrwl/workspace/src/utils/buildale-libs-utils';
|
|
||||||
|
|
||||||
export interface NodePackageBuilderOptions extends JsonObject {
|
export interface NodePackageBuilderOptions extends JsonObject {
|
||||||
main: string;
|
main: string;
|
||||||
@ -181,30 +179,13 @@ function compileTypeScriptFiles(
|
|||||||
|
|
||||||
return Observable.create((subscriber: Subscriber<BuilderOutput>) => {
|
return Observable.create((subscriber: Subscriber<BuilderOutput>) => {
|
||||||
if (projectDependencies.length > 0) {
|
if (projectDependencies.length > 0) {
|
||||||
// const parsedTSConfig = readTsConfig(tsConfigPath);
|
|
||||||
const parsedTSConfig = ts.readConfigFile(tsConfigPath, ts.sys.readFile)
|
|
||||||
.config;
|
|
||||||
|
|
||||||
// update TSConfig paths to point to the dist folder
|
|
||||||
parsedTSConfig.compilerOptions = parsedTSConfig.compilerOptions || {};
|
|
||||||
parsedTSConfig.compilerOptions.paths =
|
|
||||||
parsedTSConfig.compilerOptions.paths || {};
|
|
||||||
updatePaths(projectDependencies, parsedTSConfig.compilerOptions.paths);
|
|
||||||
|
|
||||||
// find the library root folder
|
|
||||||
const libRoot = projGraph.nodes[context.target.project].data.root;
|
const libRoot = projGraph.nodes[context.target.project].data.root;
|
||||||
|
tsConfigPath = createTmpTsConfig(
|
||||||
// write the tmp tsconfig needed for building
|
tsConfigPath,
|
||||||
const tmpTsConfigPath = join(
|
|
||||||
context.workspaceRoot,
|
context.workspaceRoot,
|
||||||
libRoot,
|
libRoot,
|
||||||
'tsconfig.lib.nx-tmp'
|
projectDependencies
|
||||||
);
|
);
|
||||||
writeJsonFile(tmpTsConfigPath, parsedTSConfig);
|
|
||||||
|
|
||||||
// adjust the tsConfig path s.t. it points to the temporary one
|
|
||||||
// with the adjusted paths
|
|
||||||
tsConfigPath = tmpTsConfigPath;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
@ -248,17 +229,7 @@ function compileTypeScriptFiles(
|
|||||||
new Error(`Could not compile Typescript files: \n ${error}`)
|
new Error(`Could not compile Typescript files: \n ${error}`)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}).pipe(
|
});
|
||||||
finalize(() => {
|
|
||||||
cleanupTmpTsConfigFile(tsConfigPath);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function cleanupTmpTsConfigFile(tsConfigPath) {
|
|
||||||
if (tsConfigPath.indexOf('.nx-tmp') > -1) {
|
|
||||||
unlinkSync(tsConfigPath);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function killProcess(context: BuilderContext): void {
|
function killProcess(context: BuilderContext): void {
|
||||||
|
|||||||
@ -0,0 +1,47 @@
|
|||||||
|
import { Tree } from '@angular-devkit/schematics';
|
||||||
|
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
||||||
|
import { readWorkspace } from '@nrwl/workspace';
|
||||||
|
|
||||||
|
import * as path from 'path';
|
||||||
|
|
||||||
|
describe('set buildLibsFromSource to true', () => {
|
||||||
|
let tree: Tree;
|
||||||
|
let schematicRunner: SchematicTestRunner;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
tree = Tree.empty();
|
||||||
|
schematicRunner = new SchematicTestRunner(
|
||||||
|
'@nrwl/web',
|
||||||
|
path.join(__dirname, '../../../migrations.json')
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(`should set buildLibsFromSource to true`, async () => {
|
||||||
|
tree.create(
|
||||||
|
'workspace.json',
|
||||||
|
JSON.stringify({
|
||||||
|
projects: {
|
||||||
|
demo: {
|
||||||
|
root: 'apps/demo',
|
||||||
|
sourceRoot: 'apps/demo/src',
|
||||||
|
architect: {
|
||||||
|
build: {
|
||||||
|
builder: '@nrwl/node:build',
|
||||||
|
options: {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
);
|
||||||
|
|
||||||
|
tree = await schematicRunner
|
||||||
|
.runSchematicAsync('set-build-libs-from-source', {}, tree)
|
||||||
|
.toPromise();
|
||||||
|
|
||||||
|
const config = readWorkspace(tree);
|
||||||
|
expect(config.projects.demo.architect.build.options).toEqual({
|
||||||
|
buildLibsFromSource: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { Rule } from '@angular-devkit/schematics';
|
||||||
|
import { updateWorkspaceInTree } from '@nrwl/workspace';
|
||||||
|
|
||||||
|
export default function update(): Rule {
|
||||||
|
return updateWorkspaceInTree(workspaceJson => {
|
||||||
|
Object.entries<any>(workspaceJson.projects).forEach(
|
||||||
|
([projectName, project]) => {
|
||||||
|
Object.entries<any>(project.architect).forEach(
|
||||||
|
([targetName, targetConfig]) => {
|
||||||
|
if (targetConfig.builder === '@nrwl/node:build') {
|
||||||
|
const architect =
|
||||||
|
workspaceJson.projects[projectName].architect[targetName];
|
||||||
|
if (architect && architect.options) {
|
||||||
|
architect.options.buildLibsFromSource = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return workspaceJson;
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -53,7 +53,8 @@
|
|||||||
},
|
},
|
||||||
"publishable": {
|
"publishable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Create a publishable library. A \"build\" architect will be added for this project the workspace configuration."
|
"description": "Create a publishable library.",
|
||||||
|
"alias": "buildable"
|
||||||
},
|
},
|
||||||
"testEnvironment": {
|
"testEnvironment": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -109,7 +109,8 @@
|
|||||||
},
|
},
|
||||||
"publishable": {
|
"publishable": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Create a publishable library. A \"build\" architect will be added for this project the workspace configuration."
|
"description": "Create a buildable library.",
|
||||||
|
"alias": "buildable"
|
||||||
},
|
},
|
||||||
"component": {
|
"component": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
|
|||||||
@ -9,6 +9,11 @@
|
|||||||
"version": "9.0.0-beta.1",
|
"version": "9.0.0-beta.1",
|
||||||
"description": "Rename @nrwl/web:bundle => @nrwl/web:package",
|
"description": "Rename @nrwl/web:bundle => @nrwl/web:package",
|
||||||
"factory": "./src/migrations/update-9-0-0/update-builder-9-0-0"
|
"factory": "./src/migrations/update-9-0-0/update-builder-9-0-0"
|
||||||
|
},
|
||||||
|
"set-build-libs-from-source": {
|
||||||
|
"version": "9.2.0-beta.1",
|
||||||
|
"description": "Set buildLibsFromSource property to true to not break existing projects.",
|
||||||
|
"factory": "./src/migrations/update-9-2-0/set-build-libs-from-source"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,142 +0,0 @@
|
|||||||
import { join } from 'path';
|
|
||||||
|
|
||||||
import { workspaces } from '@angular-devkit/core';
|
|
||||||
import { of } from 'rxjs';
|
|
||||||
import * as buildWebpack from '@angular-devkit/build-webpack';
|
|
||||||
jest.mock('tsconfig-paths-webpack-plugin');
|
|
||||||
import TsConfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
|
|
||||||
|
|
||||||
import { MockBuilderContext } from '@nrwl/workspace/testing';
|
|
||||||
|
|
||||||
import { run, WebBuildBuilderOptions } from './build.impl';
|
|
||||||
import * as webConfigUtils from '../../utils/web.config';
|
|
||||||
import { getMockContext } from '../../utils/testing';
|
|
||||||
import * as indexHtmlUtils from '../../utils/third-party/cli-files/utilities/index-file/write-index-html';
|
|
||||||
|
|
||||||
describe('WebBuildBuilder', () => {
|
|
||||||
let context: MockBuilderContext;
|
|
||||||
let testOptions: WebBuildBuilderOptions;
|
|
||||||
let runWebpack: jasmine.Spy;
|
|
||||||
let writeIndexHtml: jasmine.Spy;
|
|
||||||
|
|
||||||
beforeEach(async () => {
|
|
||||||
context = await getMockContext();
|
|
||||||
testOptions = {
|
|
||||||
index: 'apps/webapp/src/index.html',
|
|
||||||
budgets: [],
|
|
||||||
baseHref: '/',
|
|
||||||
optimization: true,
|
|
||||||
deployUrl: '/',
|
|
||||||
scripts: ['apps/webapp/src/scripts.js'],
|
|
||||||
styles: ['apps/webapp/src/styles.css'],
|
|
||||||
main: 'apps/webapp/src/main.ts',
|
|
||||||
tsConfig: 'apps/webapp/tsconfig.app.json',
|
|
||||||
outputPath: 'dist/apps/webapp',
|
|
||||||
fileReplacements: [
|
|
||||||
{
|
|
||||||
replace: 'apps/webapp/environment/environment.ts',
|
|
||||||
with: 'apps/webapp/environment/environment.prod.ts'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
replace: 'module1.ts',
|
|
||||||
with: 'module2.ts'
|
|
||||||
}
|
|
||||||
],
|
|
||||||
assets: [],
|
|
||||||
statsJson: false
|
|
||||||
};
|
|
||||||
const stats = {
|
|
||||||
stats: 'stats'
|
|
||||||
};
|
|
||||||
runWebpack = spyOn(buildWebpack, 'runWebpack').and.callFake(
|
|
||||||
(config, context, opts) => {
|
|
||||||
opts.logging({
|
|
||||||
toJson: () => stats,
|
|
||||||
toString: () => JSON.stringify(stats)
|
|
||||||
});
|
|
||||||
return of({
|
|
||||||
success: true,
|
|
||||||
emittedFiles: [
|
|
||||||
{
|
|
||||||
file: 'scripts.js',
|
|
||||||
extension: '.js'
|
|
||||||
},
|
|
||||||
{
|
|
||||||
file: 'styles.css',
|
|
||||||
extension: '.css'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
|
||||||
);
|
|
||||||
spyOn(workspaces, 'readWorkspace').and.returnValue({
|
|
||||||
workspace: {
|
|
||||||
projects: {
|
|
||||||
get: () => ({
|
|
||||||
sourceRoot: join(__dirname, '../../..')
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
spyOn(webConfigUtils, 'getWebConfig').and.returnValue({
|
|
||||||
config: 'config'
|
|
||||||
});
|
|
||||||
writeIndexHtml = spyOn(indexHtmlUtils, 'writeIndexHtml').and.returnValue(
|
|
||||||
of(null)
|
|
||||||
);
|
|
||||||
(<any>TsConfigPathsPlugin).mockImplementation(
|
|
||||||
function MockPathsPlugin() {}
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('run', () => {
|
|
||||||
it('should call runWebpack', async () => {
|
|
||||||
await run(testOptions, context).toPromise();
|
|
||||||
|
|
||||||
expect(runWebpack).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should emit success', async () => {
|
|
||||||
const buildEvent = await run(testOptions, context).toPromise();
|
|
||||||
|
|
||||||
expect(buildEvent.success).toEqual(true);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should write the HTML', async () => {
|
|
||||||
await run(testOptions, context).toPromise();
|
|
||||||
|
|
||||||
expect(writeIndexHtml).toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('differential loading', () => {
|
|
||||||
it('should call runWebpack twice', async () => {
|
|
||||||
await run(testOptions, context).toPromise();
|
|
||||||
|
|
||||||
expect(runWebpack).toHaveBeenCalledTimes(2);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('webpackConfig option', () => {
|
|
||||||
it('should require the specified function and use the return value', async () => {
|
|
||||||
const mockFunction = jest.fn(config => ({
|
|
||||||
config: 'config'
|
|
||||||
}));
|
|
||||||
jest.mock('/root/apps/webapp/webpack.config.js', () => mockFunction, {
|
|
||||||
virtual: true
|
|
||||||
});
|
|
||||||
await run(
|
|
||||||
{
|
|
||||||
...testOptions,
|
|
||||||
webpackConfig: './apps/webapp/webpack.config.js'
|
|
||||||
},
|
|
||||||
context
|
|
||||||
).toPromise();
|
|
||||||
|
|
||||||
expect(mockFunction).toHaveBeenCalled();
|
|
||||||
expect(runWebpack.calls.first().args[0]).toEqual({
|
|
||||||
config: 'config'
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
@ -5,7 +5,7 @@ import {
|
|||||||
normalize
|
normalize
|
||||||
} from '@angular-devkit/core';
|
} from '@angular-devkit/core';
|
||||||
import { BuildResult, runWebpack } from '@angular-devkit/build-webpack';
|
import { BuildResult, runWebpack } from '@angular-devkit/build-webpack';
|
||||||
import { from, Observable, of } from 'rxjs';
|
import { from, of } from 'rxjs';
|
||||||
import { normalizeWebBuildOptions } from '../../utils/normalize';
|
import { normalizeWebBuildOptions } from '../../utils/normalize';
|
||||||
import { getWebConfig } from '../../utils/web.config';
|
import { getWebConfig } from '../../utils/web.config';
|
||||||
import { BuildBuilderOptions } from '../../utils/types';
|
import { BuildBuilderOptions } from '../../utils/types';
|
||||||
@ -16,6 +16,11 @@ import { NodeJsSyncHost } from '@angular-devkit/core/node';
|
|||||||
import { execSync } from 'child_process';
|
import { execSync } from 'child_process';
|
||||||
import { Range, satisfies } from 'semver';
|
import { Range, satisfies } from 'semver';
|
||||||
import { basename } from 'path';
|
import { basename } from 'path';
|
||||||
|
import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph';
|
||||||
|
import {
|
||||||
|
calculateProjectDependencies,
|
||||||
|
createTmpTsConfig
|
||||||
|
} from '@nrwl/workspace/src/utils/buildable-libs-utils';
|
||||||
|
|
||||||
const IGNORED_WEBPACK_OUTPUT = [/WARNING in The comment file/i];
|
const IGNORED_WEBPACK_OUTPUT = [/WARNING in The comment file/i];
|
||||||
|
|
||||||
@ -38,6 +43,7 @@ export interface WebBuildBuilderOptions extends BuildBuilderOptions {
|
|||||||
subresourceIntegrity?: boolean;
|
subresourceIntegrity?: boolean;
|
||||||
|
|
||||||
verbose?: boolean;
|
verbose?: boolean;
|
||||||
|
buildLibsFromSource?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default createBuilder<WebBuildBuilderOptions & JsonObject>(run);
|
export default createBuilder<WebBuildBuilderOptions & JsonObject>(run);
|
||||||
@ -62,6 +68,21 @@ export function run(options: WebBuildBuilderOptions, context: BuilderContext) {
|
|||||||
`Node version ${nodeVersion} is not supported. Supported range is "${supportedRange.raw}".`
|
`Node version ${nodeVersion} is not supported. Supported range is "${supportedRange.raw}".`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!options.buildLibsFromSource) {
|
||||||
|
const projGraph = createProjectGraph();
|
||||||
|
const { target, dependencies } = calculateProjectDependencies(
|
||||||
|
projGraph,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
options.tsConfig = createTmpTsConfig(
|
||||||
|
options.tsConfig,
|
||||||
|
context.workspaceRoot,
|
||||||
|
target.data.root,
|
||||||
|
dependencies
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
return from(getSourceRoot(context, host))
|
return from(getSourceRoot(context, host))
|
||||||
.pipe(
|
.pipe(
|
||||||
map(sourceRoot => {
|
map(sourceRoot => {
|
||||||
|
|||||||
@ -230,6 +230,11 @@
|
|||||||
"webpackConfig": {
|
"webpackConfig": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"description": "Path to a function which takes a webpack config, some context and returns the resulting webpack config"
|
"description": "Path to a function which takes a webpack config, some context and returns the resulting webpack config"
|
||||||
|
},
|
||||||
|
"buildLibsFromSource": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Read buildable libraries from source instead of building them separately.",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"required": ["tsConfig", "main", "index"],
|
"required": ["tsConfig", "main", "index"],
|
||||||
|
|||||||
@ -5,8 +5,8 @@ import {
|
|||||||
createBuilder
|
createBuilder
|
||||||
} from '@angular-devkit/architect';
|
} from '@angular-devkit/architect';
|
||||||
import { JsonObject } from '@angular-devkit/core';
|
import { JsonObject } from '@angular-devkit/core';
|
||||||
import { from, Observable, of } from 'rxjs';
|
import { Observable, of } from 'rxjs';
|
||||||
import { switchMap, tap, last, mergeMap, catchError } from 'rxjs/operators';
|
import { catchError, last, switchMap, tap } from 'rxjs/operators';
|
||||||
import { runRollup } from './run-rollup';
|
import { runRollup } from './run-rollup';
|
||||||
import { createBabelConfig as _createBabelConfig } from '../../utils/babel-config';
|
import { createBabelConfig as _createBabelConfig } from '../../utils/babel-config';
|
||||||
import * as autoprefixer from 'autoprefixer';
|
import * as autoprefixer from 'autoprefixer';
|
||||||
@ -27,18 +27,14 @@ import {
|
|||||||
readJsonFile,
|
readJsonFile,
|
||||||
writeJsonFile
|
writeJsonFile
|
||||||
} from '@nrwl/workspace/src/utils/fileutils';
|
} from '@nrwl/workspace/src/utils/fileutils';
|
||||||
import {
|
import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph';
|
||||||
createProjectGraph,
|
|
||||||
ProjectGraphNode
|
|
||||||
} from '@nrwl/workspace/src/core/project-graph';
|
|
||||||
import {
|
import {
|
||||||
calculateProjectDependencies,
|
calculateProjectDependencies,
|
||||||
checkDependentProjectsHaveBeenBuilt,
|
checkDependentProjectsHaveBeenBuilt,
|
||||||
DependentBuildableProjectNode,
|
DependentBuildableProjectNode,
|
||||||
updateBuildableProjectPackageJsonDependencies,
|
readTsConfigWithRemappedPaths,
|
||||||
updatePaths
|
updateBuildableProjectPackageJsonDependencies
|
||||||
} from '@nrwl/workspace/src/utils/buildale-libs-utils';
|
} from '@nrwl/workspace/src/utils/buildable-libs-utils';
|
||||||
import * as ts from 'typescript';
|
|
||||||
|
|
||||||
// These use require because the ES import isn't correct.
|
// These use require because the ES import isn't correct.
|
||||||
const resolve = require('@rollup/plugin-node-resolve');
|
const resolve = require('@rollup/plugin-node-resolve');
|
||||||
@ -151,12 +147,10 @@ function createRollupOptions(
|
|||||||
context: BuilderContext,
|
context: BuilderContext,
|
||||||
packageJson: any
|
packageJson: any
|
||||||
): rollup.InputOptions {
|
): rollup.InputOptions {
|
||||||
const parsedTSConfig = ts.readConfigFile(options.tsConfig, ts.sys.readFile)
|
const parsedTSConfig = readTsConfigWithRemappedPaths(
|
||||||
.config;
|
options.tsConfig,
|
||||||
parsedTSConfig.compilerOptions = parsedTSConfig.compilerOptions || {};
|
dependencies
|
||||||
parsedTSConfig.compilerOptions.paths =
|
);
|
||||||
parsedTSConfig.compilerOptions.paths || {};
|
|
||||||
updatePaths(dependencies, parsedTSConfig.compilerOptions.paths);
|
|
||||||
|
|
||||||
const plugins = [
|
const plugins = [
|
||||||
image(),
|
image(),
|
||||||
|
|||||||
@ -1,17 +1,10 @@
|
|||||||
import { Tree } from '@angular-devkit/schematics';
|
import { Tree } from '@angular-devkit/schematics';
|
||||||
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
|
||||||
import {
|
import { readWorkspace } from '@nrwl/workspace';
|
||||||
updateJsonInTree,
|
|
||||||
readJsonInTree,
|
|
||||||
updateWorkspaceInTree,
|
|
||||||
readWorkspace,
|
|
||||||
getWorkspacePath
|
|
||||||
} from '@nrwl/workspace';
|
|
||||||
|
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
|
||||||
|
|
||||||
describe('Update 8-5-0', () => {
|
describe('set buildLibsFromSource to true', () => {
|
||||||
let tree: Tree;
|
let tree: Tree;
|
||||||
let schematicRunner: SchematicTestRunner;
|
let schematicRunner: SchematicTestRunner;
|
||||||
|
|
||||||
@ -23,7 +16,7 @@ describe('Update 8-5-0', () => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should remove differentialLoading as an option for build builder`, async () => {
|
it(`should set buildLibsFromSource to true`, async () => {
|
||||||
tree.create(
|
tree.create(
|
||||||
'workspace.json',
|
'workspace.json',
|
||||||
JSON.stringify({
|
JSON.stringify({
|
||||||
@ -34,9 +27,7 @@ describe('Update 8-5-0', () => {
|
|||||||
architect: {
|
architect: {
|
||||||
build: {
|
build: {
|
||||||
builder: '@nrwl/web:build',
|
builder: '@nrwl/web:build',
|
||||||
options: {
|
options: {}
|
||||||
differentialLoading: true
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,10 +36,12 @@ describe('Update 8-5-0', () => {
|
|||||||
);
|
);
|
||||||
|
|
||||||
tree = await schematicRunner
|
tree = await schematicRunner
|
||||||
.runSchematicAsync('update-builder-8.5.0', {}, tree)
|
.runSchematicAsync('set-build-libs-from-source', {}, tree)
|
||||||
.toPromise();
|
.toPromise();
|
||||||
|
|
||||||
const config = readWorkspace(tree);
|
const config = readWorkspace(tree);
|
||||||
expect(config.projects.demo.architect.build.options).toEqual({});
|
expect(config.projects.demo.architect.build.options).toEqual({
|
||||||
|
buildLibsFromSource: true
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -0,0 +1,23 @@
|
|||||||
|
import { Rule } from '@angular-devkit/schematics';
|
||||||
|
import { updateWorkspaceInTree } from '@nrwl/workspace';
|
||||||
|
|
||||||
|
export default function update(): Rule {
|
||||||
|
return updateWorkspaceInTree(workspaceJson => {
|
||||||
|
Object.entries<any>(workspaceJson.projects).forEach(
|
||||||
|
([projectName, project]) => {
|
||||||
|
Object.entries<any>(project.architect).forEach(
|
||||||
|
([targetName, targetConfig]) => {
|
||||||
|
if (targetConfig.builder === '@nrwl/web:build') {
|
||||||
|
const architect =
|
||||||
|
workspaceJson.projects[projectName].architect[targetName];
|
||||||
|
if (architect && architect.options) {
|
||||||
|
architect.options.buildLibsFromSource = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
return workspaceJson;
|
||||||
|
});
|
||||||
|
}
|
||||||
@ -4,7 +4,7 @@ import {
|
|||||||
ProjectType
|
ProjectType
|
||||||
} from '../core/project-graph';
|
} from '../core/project-graph';
|
||||||
import { BuilderContext } from '@angular-devkit/architect';
|
import { BuilderContext } from '@angular-devkit/architect';
|
||||||
import { join } from 'path';
|
import { join, resolve, dirname } from 'path';
|
||||||
import {
|
import {
|
||||||
fileExists,
|
fileExists,
|
||||||
readJsonFile,
|
readJsonFile,
|
||||||
@ -12,6 +12,8 @@ import {
|
|||||||
} from '@nrwl/workspace/src/utils/fileutils';
|
} from '@nrwl/workspace/src/utils/fileutils';
|
||||||
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
import { stripIndents } from '@angular-devkit/core/src/utils/literals';
|
||||||
import { getOutputsForTargetAndConfiguration } from '@nrwl/workspace/src/tasks-runner/utils';
|
import { getOutputsForTargetAndConfiguration } from '@nrwl/workspace/src/tasks-runner/utils';
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
import { unlinkSync } from 'fs';
|
||||||
|
|
||||||
function isBuildable(target: string, node: ProjectGraphNode): boolean {
|
function isBuildable(target: string, node: ProjectGraphNode): boolean {
|
||||||
return (
|
return (
|
||||||
@ -33,10 +35,13 @@ export function calculateProjectDependencies(
|
|||||||
): { target: ProjectGraphNode; dependencies: DependentBuildableProjectNode[] } {
|
): { target: ProjectGraphNode; dependencies: DependentBuildableProjectNode[] } {
|
||||||
const target = projGraph.nodes[context.target.project];
|
const target = projGraph.nodes[context.target.project];
|
||||||
// gather the library dependencies
|
// gather the library dependencies
|
||||||
const dependencies = (projGraph.dependencies[context.target.project] || [])
|
const dependencies = recursivelyCollectDependencies(
|
||||||
.map(dependency => {
|
context.target.project,
|
||||||
const depNode = projGraph.nodes[dependency.target];
|
projGraph,
|
||||||
|
[]
|
||||||
|
)
|
||||||
|
.map(dep => {
|
||||||
|
const depNode = projGraph.nodes[dep];
|
||||||
if (
|
if (
|
||||||
depNode.type === ProjectType.lib &&
|
depNode.type === ProjectType.lib &&
|
||||||
isBuildable(context.target.target, depNode)
|
isBuildable(context.target.target, depNode)
|
||||||
@ -62,6 +67,83 @@ export function calculateProjectDependencies(
|
|||||||
return { target, dependencies };
|
return { target, dependencies };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function recursivelyCollectDependencies(
|
||||||
|
project: string,
|
||||||
|
projGraph: ProjectGraph,
|
||||||
|
acc: string[]
|
||||||
|
) {
|
||||||
|
(projGraph.dependencies[project] || []).forEach(dependency => {
|
||||||
|
if (acc.indexOf(dependency.target) === -1) {
|
||||||
|
acc.push(dependency.target);
|
||||||
|
recursivelyCollectDependencies(dependency.target, projGraph, acc);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return acc;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function readTsConfigWithRemappedPaths(
|
||||||
|
tsConfig: string,
|
||||||
|
dependencies: DependentBuildableProjectNode[]
|
||||||
|
) {
|
||||||
|
const parsedTSConfig = ts.readConfigFile(tsConfig, ts.sys.readFile).config;
|
||||||
|
parsedTSConfig.compilerOptions = parsedTSConfig.compilerOptions || {};
|
||||||
|
parsedTSConfig.compilerOptions.paths = readPaths(tsConfig) || {};
|
||||||
|
updatePaths(dependencies, parsedTSConfig.compilerOptions.paths);
|
||||||
|
return parsedTSConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
function readPaths(tsConfig: string) {
|
||||||
|
try {
|
||||||
|
const parsedTSConfig = ts.readConfigFile(tsConfig, ts.sys.readFile).config;
|
||||||
|
if (
|
||||||
|
parsedTSConfig.compilerOptions &&
|
||||||
|
parsedTSConfig.compilerOptions.paths
|
||||||
|
) {
|
||||||
|
return parsedTSConfig.compilerOptions.paths;
|
||||||
|
} else if (parsedTSConfig.extends) {
|
||||||
|
return readPaths(resolve(dirname(tsConfig), parsedTSConfig.extends));
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function createTmpTsConfig(
|
||||||
|
tsconfigPath: string,
|
||||||
|
workspaceRoot: string,
|
||||||
|
projectRoot: string,
|
||||||
|
dependencies: DependentBuildableProjectNode[]
|
||||||
|
) {
|
||||||
|
const parsedTSConfig = readTsConfigWithRemappedPaths(
|
||||||
|
tsconfigPath,
|
||||||
|
dependencies
|
||||||
|
);
|
||||||
|
const tmpTsConfigPath = join(workspaceRoot, projectRoot, 'tsconfig.nx-tmp');
|
||||||
|
process.on('exit', () => {
|
||||||
|
cleanupTmpTsConfigFile(tmpTsConfigPath);
|
||||||
|
});
|
||||||
|
process.on('SIGTERM', () => {
|
||||||
|
cleanupTmpTsConfigFile(tmpTsConfigPath);
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
process.on('SIGINT', () => {
|
||||||
|
cleanupTmpTsConfigFile(tmpTsConfigPath);
|
||||||
|
process.exit(0);
|
||||||
|
});
|
||||||
|
writeJsonFile(tmpTsConfigPath, parsedTSConfig);
|
||||||
|
return join(projectRoot, 'tsconfig.nx-tmp');
|
||||||
|
}
|
||||||
|
|
||||||
|
function cleanupTmpTsConfigFile(tmpTsConfigPath) {
|
||||||
|
try {
|
||||||
|
if (tmpTsConfigPath) {
|
||||||
|
unlinkSync(tmpTsConfigPath);
|
||||||
|
}
|
||||||
|
} catch (e) {}
|
||||||
|
}
|
||||||
|
|
||||||
export function checkDependentProjectsHaveBeenBuilt(
|
export function checkDependentProjectsHaveBeenBuilt(
|
||||||
context: BuilderContext,
|
context: BuilderContext,
|
||||||
projectDependencies: DependentBuildableProjectNode[]
|
projectDependencies: DependentBuildableProjectNode[]
|
||||||
@ -86,9 +168,7 @@ export function checkDependentProjectsHaveBeenBuilt(
|
|||||||
}'s dependencies have not been built yet. Please build these libraries before:
|
}'s dependencies have not been built yet. Please build these libraries before:
|
||||||
${depLibsToBuildFirst.map(x => ` - ${x.node.name}`).join('\n')}
|
${depLibsToBuildFirst.map(x => ` - ${x.node.name}`).join('\n')}
|
||||||
|
|
||||||
Try: nx run-many --target ${context.target.target} --projects ${
|
Try: nx run ${context.target.project}:${context.target.target} --with-deps
|
||||||
context.target.project
|
|
||||||
},...
|
|
||||||
`);
|
`);
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
Loading…
x
Reference in New Issue
Block a user