Compare commits

...

11 Commits

Author SHA1 Message Date
Jason Jean b030a761a8 Release 10.4.6 2020-12-10 15:28:38 -05:00
Jason Jean 6b9942f5af fix(core): decorate angular cli to error when ng update is used 2020-12-10 15:24:33 -05:00
Jason Jean ceac479da3 Release 10.4.5 2020-12-10 14:59:28 -05:00
Victor Savkin 5f0bf8a37d feat(core): update the update npm script to invoke nx migrate 2020-12-09 15:15:14 -05:00
Victor Savkin da05843b84 feat(core): show a warning about using ng update insteda of nx migrate 2020-12-09 14:42:21 -05:00
Jonathan Cammisuli 021c842677 feat(node): add generatePackageJson option to build executor
(cherry picked from commit 2ec6848dd3)
2020-12-09 10:41:54 -05:00
Victor Savkin cb81c1cd62 Release 10.4.4 2020-11-18 10:27:10 -05:00
Victor Savkin 344e16005d cleanup(core): update the error message when migration fails 2020-11-18 10:25:35 -05:00
Victor Savkin 5023a8bf59 Release 10.4.3 2020-11-18 10:06:01 -05:00
Victor Savkin cbd404ccd1 fix(core): add explicit dep on cli if missing 2020-11-18 10:03:26 -05:00
Victor Savkin 95889a2447 fix(core): migration should fetch packages using cwd instead of prefix 2020-11-18 10:03:24 -05:00
21 changed files with 285 additions and 47 deletions
+8
View File
@@ -54,6 +54,14 @@ Type: `string`
undefined
### generatePackageJson
Default: `false`
Type: `boolean`
Generates a package.json file with the project's node_module dependencies populated for installing in a container. If a package.json exists in the project's directory, it will be reused with dependencies populated.
### main
Type: `string`
+8
View File
@@ -55,6 +55,14 @@ Type: `string`
undefined
### generatePackageJson
Default: `false`
Type: `boolean`
Generates a package.json file with the project's node_module dependencies populated for installing in a container. If a package.json exists in the project's directory, it will be reused with dependencies populated.
### main
Type: `string`
+8
View File
@@ -55,6 +55,14 @@ Type: `string`
undefined
### generatePackageJson
Default: `false`
Type: `boolean`
Generates a package.json file with the project's node_module dependencies populated for installing in a container. If a package.json exists in the project's directory, it will be reused with dependencies populated.
### main
Type: `string`
+25
View File
@@ -246,6 +246,31 @@ forEachCli((currentCLIName) => {
}, 120000);
});
describe('Build Node apps', () => {
it('should generate a package.json with the `--generatePackageJson` flag', async () => {
ensureProject();
const nestapp = uniq('nestapp');
runCLI(`generate @nrwl/nest:app ${nestapp} --linter=eslint`);
await runCLIAsync(`build ${nestapp} --generatePackageJson`);
checkFilesExist(`dist/apps/${nestapp}/package.json`);
const packageJson = JSON.parse(
readFile(`dist/apps/${nestapp}/package.json`)
);
expect(packageJson).toEqual(
expect.objectContaining({
dependencies: {
'@nestjs/common': '^7.0.0',
'@nestjs/core': '^7.0.0',
},
main: 'main.js',
name: expect.any(String),
version: '0.0.1',
})
);
});
});
describe('Node Libraries', () => {
it('should be able to generate a node library', async () => {
ensureProject();
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "@nrwl/nx-source",
"version": "10.4.2",
"version": "10.4.6",
"description": "Extensible Dev Tools for Monorepos",
"homepage": "https://nx.dev",
"main": "index.js",
+20 -1
View File
@@ -9,6 +9,7 @@ import { parseRunOneOptions } from './parse-run-one-options';
* @param workspace Relevant local workspace properties
*/
process.env.NX_CLI_SET = 'true';
export function initLocal(workspace: Workspace) {
require('@nrwl/workspace/' + 'src/utils/perf-logging');
const supportedNxCommands = require('@nrwl/workspace/' +
@@ -24,7 +25,25 @@ export function initLocal(workspace: Workspace) {
.argv;
} else {
if (runOpts === false || process.env.NX_SKIP_TASKS_RUNNER) {
loadCli(workspace);
if (workspace.type === 'angular' && process.argv[2] === 'update') {
console.log(
`Nx provides a much improved version of "ng update". It runs the same migrations, but allows you to:`
);
console.log(`- rerun the same migration multiple times`);
console.log(`- reorder migrations`);
console.log(`- skip migrations`);
console.log(`- fix migrations that "almost work"`);
console.log(`- commit a partially migrated state`);
console.log(`- change versions of packages to match org requirements`);
console.log(
`And, in general, it is lot more reliable for non-trivial workspaces. Read more at: https://nx.dev/latest/angular/workspace/update`
);
console.log(
`Run "nx migrate latest" to update to the latest version of Nx.`
);
} else {
loadCli(workspace);
}
} else {
require('@nrwl/workspace' + '/src/command-line/run-one').runOne(runOpts);
}
+28 -17
View File
@@ -4,10 +4,10 @@ import { runWebpack, BuildResult } from '@angular-devkit/build-webpack';
import { Observable, from } from 'rxjs';
import { join, resolve } from 'path';
import { map, concatMap } from 'rxjs/operators';
import { concatMap, map, tap } from 'rxjs/operators';
import { getNodeWebpackConfig } from '../../utils/node.config';
import { OUT_FILENAME } from '../../utils/config';
import { BuildBuilderOptions } from '../../utils/types';
import { BuildNodeBuilderOptions } from '../../utils/types';
import { normalizeBuildOptions } from '../../utils/normalize';
import { NodeJsSyncHost } from '@angular-devkit/core/node';
import { createProjectGraph } from '@nrwl/workspace/src/core/project-graph';
@@ -15,18 +15,12 @@ import {
calculateProjectDependencies,
createTmpTsConfig,
} from '@nrwl/workspace/src/utils/buildable-libs-utils';
import { generatePackageJson } from '../../utils/generate-package-json';
try {
require('dotenv').config();
} catch (e) {}
export interface BuildNodeBuilderOptions extends BuildBuilderOptions {
optimization?: boolean;
sourceMap?: boolean;
externalDependencies: 'all' | 'none' | string[];
buildLibsFromSource?: boolean;
}
export type NodeBuildEvent = BuildResult & {
outfile: string;
};
@@ -37,8 +31,8 @@ function run(
options: JsonObject & BuildNodeBuilderOptions,
context: BuilderContext
): Observable<NodeBuildEvent> {
const projGraph = createProjectGraph();
if (!options.buildLibsFromSource) {
const projGraph = createProjectGraph();
const { target, dependencies } = calculateProjectDependencies(
projGraph,
context
@@ -51,10 +45,24 @@ function run(
);
}
return from(getSourceRoot(context)).pipe(
map((sourceRoot) =>
normalizeBuildOptions(options, context.workspaceRoot, sourceRoot)
return from(getRoots(context)).pipe(
map(({ sourceRoot, projectRoot }) =>
normalizeBuildOptions(
options,
context.workspaceRoot,
sourceRoot,
projectRoot
)
),
tap((normalizedOptions) => {
if (normalizedOptions.generatePackageJson) {
generatePackageJson(
context.target.project,
projGraph,
normalizedOptions
);
}
}),
map((options) => {
let config = getNodeWebpackConfig(options);
if (options.webpackConfig) {
@@ -84,17 +92,20 @@ function run(
);
}
async function getSourceRoot(context: BuilderContext) {
async function getRoots(
context: BuilderContext
): Promise<{ sourceRoot: string; projectRoot: string }> {
const workspaceHost = workspaces.createWorkspaceHost(new NodeJsSyncHost());
const { workspace } = await workspaces.readWorkspace(
context.workspaceRoot,
workspaceHost
);
if (workspace.projects.get(context.target.project).sourceRoot) {
return workspace.projects.get(context.target.project).sourceRoot;
const project = workspace.projects.get(context.target.project);
if (project.sourceRoot && project.root) {
return { sourceRoot: project.sourceRoot, projectRoot: project.root };
} else {
context.reportStatus('Error');
const message = `${context.target.project} does not have a sourceRoot. Please define one.`;
const message = `${context.target.project} does not have a sourceRoot or root. Please define one.`;
context.logger.error(message);
throw new Error(message);
}
@@ -117,6 +117,11 @@
"type": "boolean",
"description": "Read buildable libraries from source instead of building them separately.",
"default": false
},
"generatePackageJson": {
"type": "boolean",
"description": "Generates a package.json file with the project's node_module dependencies populated for installing in a container. If a package.json exists in the project's directory, it will be reused with dependencies populated.",
"default": false
}
},
"required": ["tsConfig", "main"],
@@ -0,0 +1,73 @@
import { ProjectGraph, readJsonFile } from '@nrwl/workspace';
import { BuildNodeBuilderOptions } from './types';
import { writeJsonFile } from '@nrwl/workspace/src/utils/fileutils';
import { OUT_FILENAME } from './config';
/**
* Creates a package.json in the output directory for support to install dependencies within containers.
*
* If a package.json exists in the project, it will reuse that.
*
* @param projectName
* @param graph
* @param options
* @constructor
*/
export function generatePackageJson(
projectName: string,
graph: ProjectGraph,
options: BuildNodeBuilderOptions
) {
const npmDeps = findAllNpmDeps(projectName, graph);
// default package.json if one does not exist
let packageJson = {
name: projectName,
version: '0.0.1',
main: OUT_FILENAME,
dependencies: {},
};
try {
packageJson = readJsonFile(`${options.projectRoot}/package.json`);
if (!packageJson.dependencies) {
packageJson.dependencies = {};
}
} catch (e) {}
const rootPackageJson = readJsonFile(`${options.root}/package.json`);
Object.entries(npmDeps).forEach(([packageName, version]) => {
// don't include devDeps
if (rootPackageJson.devDependencies?.[packageName]) {
return;
}
packageJson.dependencies[packageName] = version;
});
writeJsonFile(`${options.outputPath}/package.json`, packageJson);
}
function findAllNpmDeps(
projectName: string,
graph: ProjectGraph,
list: { [packageName: string]: string } = {},
seen = new Set<string>()
) {
if (seen.has(projectName)) {
return list;
}
seen.add(projectName);
const node = graph.nodes[projectName];
if (node.type === 'npm') {
list[node.data.packageName] = node.data.version;
}
graph.dependencies[projectName]?.forEach((dep) => {
findAllNpmDeps(dep.target, graph, list, seen);
});
return list;
}
+1 -2
View File
@@ -1,8 +1,7 @@
import { getNodeWebpackConfig } from './node.config';
import { BannerPlugin } from 'webpack';
jest.mock('tsconfig-paths-webpack-plugin');
import TsConfigPathsPlugin from 'tsconfig-paths-webpack-plugin';
import { BuildNodeBuilderOptions } from '../builders/build/build.impl';
import { BuildNodeBuilderOptions } from './types';
describe('getNodePartial', () => {
let input: BuildNodeBuilderOptions;
+2 -2
View File
@@ -1,9 +1,9 @@
import { Configuration, BannerPlugin } from 'webpack';
import { Configuration } from 'webpack';
import * as mergeWebpack from 'webpack-merge';
import * as nodeExternals from 'webpack-node-externals';
import { BuildNodeBuilderOptions } from '../builders/build/build.impl';
import { getBaseWebpackPartial } from './config';
import { BuildNodeBuilderOptions } from './types';
function getNodePartial(options: BuildNodeBuilderOptions) {
const webpackConfig: Configuration = {
+34 -6
View File
@@ -8,6 +8,7 @@ describe('normalizeBuildOptions', () => {
let testOptions: BuildBuilderOptions;
let root: string;
let sourceRoot: Path;
let projectRoot: string;
beforeEach(() => {
testOptions = {
@@ -29,24 +30,45 @@ describe('normalizeBuildOptions', () => {
};
root = '/root';
sourceRoot = normalize('apps/nodeapp/src');
projectRoot = 'apps/nodeapp';
});
it('should add the root', () => {
const result = normalizeBuildOptions(testOptions, root, sourceRoot);
const result = normalizeBuildOptions(
testOptions,
root,
sourceRoot,
projectRoot
);
expect(result.root).toEqual('/root');
});
it('should resolve main from root', () => {
const result = normalizeBuildOptions(testOptions, root, sourceRoot);
const result = normalizeBuildOptions(
testOptions,
root,
sourceRoot,
projectRoot
);
expect(result.main).toEqual('/root/apps/nodeapp/src/main.ts');
});
it('should resolve the output path', () => {
const result = normalizeBuildOptions(testOptions, root, sourceRoot);
const result = normalizeBuildOptions(
testOptions,
root,
sourceRoot,
projectRoot
);
expect(result.outputPath).toEqual('/root/dist/apps/nodeapp');
});
it('should resolve the tsConfig path', () => {
const result = normalizeBuildOptions(testOptions, root, sourceRoot);
const result = normalizeBuildOptions(
testOptions,
root,
sourceRoot,
projectRoot
);
expect(result.tsConfig).toEqual('/root/apps/nodeapp/tsconfig.app.json');
});
@@ -69,7 +91,8 @@ describe('normalizeBuildOptions', () => {
],
},
root,
sourceRoot
sourceRoot,
projectRoot
);
expect(result.assets).toEqual([
{
@@ -87,7 +110,12 @@ describe('normalizeBuildOptions', () => {
});
it('should resolve the file replacement paths', () => {
const result = normalizeBuildOptions(testOptions, root, sourceRoot);
const result = normalizeBuildOptions(
testOptions,
root,
sourceRoot,
projectRoot
);
expect(result.fileReplacements).toEqual([
{
replace: '/root/apps/environment/environment.ts',
+6 -4
View File
@@ -1,4 +1,4 @@
import { Path, normalize } from '@angular-devkit/core';
import { normalize } from '@angular-devkit/core';
import { resolve, dirname, relative, basename } from 'path';
import { BuildBuilderOptions } from './types';
import { statSync } from 'fs';
@@ -11,12 +11,14 @@ export interface FileReplacement {
export function normalizeBuildOptions<T extends BuildBuilderOptions>(
options: T,
root: string,
sourceRoot: string
sourceRoot: string,
projectRoot: string
): T {
return {
...options,
root: root,
sourceRoot: sourceRoot,
root,
sourceRoot,
projectRoot,
main: resolve(root, options.main),
outputPath: resolve(root, options.outputPath),
tsConfig: resolve(root, options.tsConfig),
+9
View File
@@ -41,4 +41,13 @@ export interface BuildBuilderOptions {
root?: string;
sourceRoot?: Path;
projectRoot?: string;
}
export interface BuildNodeBuilderOptions extends BuildBuilderOptions {
optimization?: boolean;
sourceMap?: boolean;
externalDependencies: 'all' | 'none' | string[];
buildLibsFromSource?: boolean;
generatePackageJson?: boolean;
}
+3 -5
View File
@@ -419,8 +419,9 @@ function createFetcher(packageManager: string, logger: logging.Logger) {
const dir = dirSync().name;
logger.info(`Fetching ${packageName}@${packageVersion}`);
const install = getPackageManagerInstallCommand(packageManager);
execSync(`${install} ${packageName}@${packageVersion} --prefix=${dir}`, {
execSync(`${install} ${packageName}@${packageVersion}`, {
stdio: [],
cwd: dir,
});
const packageJsonPath = require.resolve(`${packageName}/package.json`, {
paths: [dir],
@@ -564,14 +565,11 @@ async function generateMigrationsJsonAndUpdatePackageJson(
);
}
} catch (e) {
const startVersion = versions(root, {})('@nrwl/workspace');
const installDev = getPackageManagerInstallCommand(packageManager, true);
logger.error(
`NX The migrate command failed. Try the following to migrate your workspace:`
);
logger.error(`> ${installDev} @nrwl/workspace@latest`);
logger.error(
`> nx migrate ${opts.targetPackage}@${opts.targetVersion} --from="@nrwl/workspace@${startVersion}"`
`> npx @nrwl/tao@latest migrate ${opts.targetPackage}@${opts.targetVersion}`
);
logger.error(
`This will use the newest version of the migrate functionality, which might have your issue resolved.`
+10
View File
@@ -134,6 +134,16 @@
"version": "10.4.0-beta.5",
"description": "Add an explicit dependency on @nrwl/tao",
"factory": "./src/migrations/update-10-4-0/add-explicit-dep-on-tao"
},
"update-script-to-invoke-nx-migrate": {
"version": "10.4.5",
"description": "Update the 'update' npm script to invoke nx migrate",
"factory": "./src/migrations/update-10-4-0/update-script-to-invoke-nx-migrate"
},
"update-decorate-angular-cli": {
"version": "10.4.6",
"description": "Update the decoration script when using Angular CLI",
"factory": "./src/migrations/update-10-4-0/update-decorate-angular-cli"
}
},
"packageJsonUpdates": {
@@ -4,7 +4,10 @@ import { nxVersion } from '../../../src/utils/versions';
export default function update(): Rule {
return chain([
addDepsToPackageJson({}, { '@nrwl/tao': nxVersion }),
addDepsToPackageJson(
{},
{ '@nrwl/tao': nxVersion, '@nrwl/cli': nxVersion }
),
formatFiles(),
]);
}
@@ -0,0 +1,21 @@
import { join as pathJoin } from 'path';
import { readFileSync } from 'fs';
import { Tree } from '@angular-devkit/schematics';
export default function update() {
return (host: Tree) => {
const decorateCli = readFileSync(
pathJoin(
__dirname as any,
'..',
'..',
'schematics',
'utils',
'decorate-angular-cli.js__tmpl__'
)
).toString();
if (host.exists('/decorate-angular-cli.js')) {
host.overwrite('/decorate-angular-cli.js', decorateCli);
}
};
}
@@ -0,0 +1,11 @@
import { Rule } from '@angular-devkit/schematics';
import { updateJsonInTree } from '@nrwl/workspace';
export default function update(): Rule {
return updateJsonInTree('package.json', (json) => {
if (json.scripts && json.scripts.update) {
json.scripts.update = 'nx migrate latest';
}
return json;
});
}
@@ -50,6 +50,14 @@ if (!process.env['NX_CLI_SET']) {
const { output } = require('@nrwl/workspace');
output.warn({ title: 'The Angular CLI was invoked instead of the Nx CLI. Use "npx ng [command]" or "nx [command]" instead.' });
}
if (process.argv[2] === 'update') {
const { output } = require('@nrwl/workspace');
output.error({
title: '"ng update" is deprecated in favor of "nx migrate". Read more: https://nx.dev/latest/angular/workspace/update'
});
throw new Error();
}
${angularCLIInit}
`);
}
@@ -24,15 +24,7 @@
"format": "nx format:write",
"format:write": "nx format:write",
"format:check": "nx format:check",
<% if(cli === 'angular') { %>
"update": "ng update @nrwl/workspace",
<% } %>
<% if(cli === 'nx') { %>
"update": "nx migrate latest",
<% } %>
"workspace-schematic": "nx workspace-schematic",
"dep-graph": "nx dep-graph",
"help": "nx help"