Compare commits

...

12 Commits

Author SHA1 Message Date
Jason Jean 87b2b5c085 chore(misc): publish 15.2.1 2022-11-18 19:44:48 -05:00
Jason Jean 89f8a53578 fix(core): use multiselect prompts for array properties (#13270)
(cherry picked from commit 3af70fc647)
2022-11-18 19:42:03 -05:00
Jason Jean b402abe239 chore(repo): fix issues building nx-dev
(cherry picked from commit 55c20b81c0)
2022-11-18 19:06:41 -05:00
Jason Jean e85804fa41 chore(repo): fix includedScripts typo
(cherry picked from commit 33154c344f)
2022-11-18 19:06:39 -05:00
Victor Savkin 7f8af1a8ae chore(repo): use root-level scripts
(cherry picked from commit ffd40af446)
2022-11-18 18:25:34 -05:00
Katerina Skroumpelou b1c05fee48 fix(bundling): file replacement for vite (#13255)
(cherry picked from commit e4092aa47f)
2022-11-18 18:20:56 -05:00
Katerina Skroumpelou 22d9031b96 fix(bundling): remove the vue options from vite gen (#13221)
(cherry picked from commit ab93817d44)
2022-11-18 18:20:50 -05:00
Colum Ferry aa2ee2d326 fix(angular): should support filereplacements for apps that already have them (#13247)
(cherry picked from commit b4fb074a09)
2022-11-18 18:20:47 -05:00
Miroslav Jonaš 951a364a13 cleanup(core): move lock-file utils to root nx level (#13245)
(cherry picked from commit b2b161cb8d)
2022-11-18 18:20:43 -05:00
Colum Ferry 1b9c7df62c fix(angular): setup-ssr environments file replacements should be removed (#13244)
(cherry picked from commit b88dc35aa5)
2022-11-18 18:20:34 -05:00
Colum Ferry 4c2e5aaf00 fix(angular): setup-ssr should output correct outpathPath for server build (#13243)
(cherry picked from commit e041223020)
2022-11-18 18:20:32 -05:00
Michał Mrozek c0ee01f924 fix(angular): local imports in webpack-dev-server custom config (#13156)
(cherry picked from commit e971ffba71)
2022-11-18 18:20:28 -05:00
39 changed files with 178 additions and 302 deletions
+7 -7
View File
@@ -176,7 +176,7 @@ jobs:
- run: npx nx-cloud start-ci-run --stop-agents-after="e2e"
- run:
name: Check Documentation
command: npx nx-cloud record yarn documentation
command: npx nx documentation --no-dte
no_output_timeout: 20m
- run:
name: Run Checks/Lint/Test/Build
@@ -184,12 +184,12 @@ jobs:
command: |
pids=()
(npx nx-cloud record yarn check-imports &&
npx nx-cloud record yarn nx format:check --base=$NX_BASE --head=$NX_HEAD &&
npx nx-cloud record yarn check-commit &&
npx nx-cloud record yarn check-lock-files &&
npx nx-cloud record yarn nx workspace-lint &&
npx nx-cloud record yarn depcheck) &
(npx nx check-imports --no-dte &&
npx nx-cloud record -- nx format:check --base=$NX_BASE --head=$NX_HEAD &&
npx nx check-commit --no-dte &&
npx nx check-lock-files --no-dte &&
npx nx lint --no-dte &&
npx nx depcheck --no-dte ) &
pids+=($!)
yarn nx affected --target=lint --base=$NX_BASE --head=$NX_HEAD --parallel=3 &
+1
View File
@@ -14,6 +14,7 @@ packages/react/src/schematics/**/files/**/*.json
packages/jest/src/schematics/**/files/**/*.json
packages/**/schematics/**/files/**/*.html
packages/**/generators/**/files/**/*.html
nx-dev/nx-dev/.next/
/.vscode
/.idea
/.github
+1 -1
View File
@@ -250,7 +250,7 @@ Please follow the following guidelines:
- Debug with `node --inspect-brk ./node_modules/jest/bin/jest.js build/packages/angular/src/utils/ast-utils.spec.js`
- Make sure e2e tests pass (this can take a while, so you can always let CI check those) (`nx affected --target=e2e`)
- Target a specific e2e test with `nx e2e e2e-cypress`
- Make sure you run `yarn format`
- Make sure you run `nx format`
- Update documentation with `yarn documentation`. For documentation, check for spelling and grammatical errors.
- Update your commit message to follow the guidelines below (use `yarn commit` to automate compliance)
- `yarn check-commit` will check to make sure your commit messages are formatted correctly
+1 -1
View File
@@ -28,7 +28,7 @@
"uiFramework": {
"type": "string",
"description": "UI Framework to use for Vite.",
"enum": ["react", "vue3", "vue3-jsx"],
"enum": ["react", "none"],
"default": "react",
"x-prompt": "What UI framework plugin should Vite use?"
}
+1 -1
View File
@@ -1,6 +1,6 @@
{
"packages": ["build/packages/*"],
"version": "15.2.0",
"version": "15.2.1",
"granularPathspec": false,
"command": {
"publish": {
+1 -8
View File
@@ -3,7 +3,6 @@
"affected": {
"defaultBase": "master"
},
"npmScope": "nrwl",
"tasksRunnerOptions": {
"default": {
"runner": "@nrwl/nx-cloud",
@@ -86,11 +85,5 @@
"inputs": ["default", "^production", "{workspaceRoot}/.storybook/**/*"]
}
},
"generators": {
"@nrwl/react": {
"application": {
"babel": true
}
}
}
"defaultProject": "@nrwl/nx-source"
}
+14 -3
View File
@@ -10,11 +10,9 @@
"check-format": "nx format:check --all",
"check-imports": "node ./scripts/check-imports.js",
"check-lock-files": "node ./scripts/check-lock-files.js",
"check-versions": "ts-node -P ./scripts/tsconfig.scripts.json ./scripts/check-versions.ts",
"check-documentation-map": "ts-node -P ./scripts/tsconfig.scripts.json ./scripts/documentation/map-link-checker.ts",
"e2e-start-local-registry": "node ./scripts/e2e-start-local-registry.js",
"e2e-build-package-publish": "ts-node -P ./scripts/tsconfig.e2e.json ./scripts/e2e-build-package-publish.ts",
"format": "nx format",
"nx-release": "ts-node -P ./scripts/tsconfig.scripts.json ./scripts/nx-release",
"prepublishOnly": "node ./scripts/update-package-group.js",
"version": "npx prettier lerna.json --write",
@@ -23,7 +21,8 @@
"documentation": "ts-node -P scripts/tsconfig.scripts.json ./scripts/documentation/documentation.ts && yarn check-documentation-map",
"submit-plugin": "node ./scripts/submit-plugin.js",
"prepare": "is-ci || husky install",
"echo": "echo 123458"
"echo": "echo 123458",
"lint": "nx workspace-lint"
},
"devDependencies": {
"@angular-devkit/architect": "~0.1500.0",
@@ -308,6 +307,18 @@
"**/xmlhttprequest-ssl": "~1.6.2",
"minimist": "^1.2.6",
"underscore": "^1.12.1"
},
"nx": {
"includedScripts": [
"echo",
"check-commit",
"check-format",
"check-imports",
"check-lock-files",
"depcheck",
"documentation",
"lint"
]
}
}
@@ -84,6 +84,12 @@ export function executeWebpackDevServerBuilder(
options.tsConfig = tsConfigPath;
return options;
};
// The buildTargetConfiguration also needs to use the generated tsconfig path
// otherwise the build will fail if customWebpack function/file is referencing
// local libs. This synchronize the behavior with webpack-browser and
// webpack-server implementation.
buildTargetConfiguration.tsConfig = tsConfigPath;
}
return executeDevServerBuilder(options as DevServerBuilderOptions, context, {
@@ -9,12 +9,6 @@ Object {
"sourceMap": true,
},
"production": Object {
"fileReplacements": Array [
Object {
"replace": "apps/app1/src/environments/environment.ts",
"with": "apps/app1/src/environments/environment.prod.ts",
},
],
"outputHashing": "media",
},
},
@@ -22,7 +16,7 @@ Object {
"executor": "@angular-devkit/build-angular:server",
"options": Object {
"main": "apps/app1/server.ts",
"outputPath": "dist/apps/apps/app1/server",
"outputPath": "dist/apps/app1/server",
"tsConfig": "apps/app1/tsconfig.server.json",
},
}
@@ -90,3 +84,31 @@ if (moduleFilename === __filename || moduleFilename.includes('iisnode')) {
export * from './src/main.server';"
`;
exports[`setupSSR should use fileReplacements if they already exist 1`] = `
Object {
"configurations": Object {
"development": Object {
"extractLicenses": false,
"optimization": false,
"sourceMap": true,
},
"production": Object {
"fileReplacements": Array [
Object {
"replace": "apps/app1/src/environments/environment.ts",
"with": "apps/app1/src/environments/environment.prod.ts",
},
],
"outputHashing": "media",
},
},
"defaultConfiguration": "production",
"executor": "@angular-devkit/build-angular:server",
"options": Object {
"main": "apps/app1/server.ts",
"outputPath": "dist/apps/app1/server",
"tsConfig": "apps/app1/tsconfig.server.json",
},
}
`;
@@ -7,13 +7,5 @@
*/
import '@angular/platform-server/init';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
export { <%= rootModuleClassName %> } from './app/<%= rootModuleFileName.slice(0, -3) %>';
export { renderModule } from '@angular/platform-server';
@@ -1,12 +1,6 @@
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
function bootstrap() {
platformBrowserDynamic()
@@ -11,28 +11,22 @@ export function updateProjectConfig(tree: Tree, schema: Schema) {
projectConfig.targets.build.options.outputPath = `dist/apps/${schema.project}/browser`;
const buildTargetFileReplacements =
projectConfig.targets.build.configurations?.production?.fileReplacements;
projectConfig.targets.server = {
executor: '@angular-devkit/build-angular:server',
options: {
outputPath: `dist/apps/${projectConfig.root}/server`,
outputPath: `dist/${projectConfig.root}/server`,
main: joinPathFragments(projectConfig.root, schema.serverFileName),
tsConfig: joinPathFragments(projectConfig.root, 'tsconfig.server.json'),
},
configurations: {
production: {
outputHashing: 'media',
fileReplacements: [
{
replace: joinPathFragments(
projectConfig.sourceRoot,
'environments/environment.ts'
),
with: joinPathFragments(
projectConfig.sourceRoot,
'environments/environment.prod.ts'
),
},
],
...(buildTargetFileReplacements
? { fileReplacements: buildTargetFileReplacements }
: {}),
},
development: {
optimization: false,
@@ -1,4 +1,8 @@
import { readJson, readProjectConfiguration } from '@nrwl/devkit';
import {
readJson,
readProjectConfiguration,
updateProjectConfiguration,
} from '@nrwl/devkit';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { PackageJson } from 'nx/src/utils/package-json';
import { angularVersion, ngUniversalVersion } from '../../utils/versions';
@@ -34,27 +38,13 @@ describe('setupSSR', () => {
*/
import '@angular/platform-server/init';
import { enableProdMode } from '@angular/core';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
export { AppServerModule } from './app/app.server.module';
export { renderModule } from '@angular/platform-server';"
`);
expect(tree.read('apps/app1/src/main.ts', 'utf-8')).toMatchInlineSnapshot(`
"import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
"import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
import { environment } from './environments/environment';
if (environment.production) {
enableProdMode();
}
function bootstrap() {
platformBrowserDynamic()
@@ -140,4 +130,32 @@ describe('setupSSR', () => {
expect(packageJson.devDependencies[dep]).toEqual(version);
}
});
it('should use fileReplacements if they already exist', async () => {
// ARRANGE
const tree = createTreeWithEmptyWorkspace();
await applicationGenerator(tree, {
name: 'app1',
});
tree.write('apps/app1/src/environments/environment.ts', '');
tree.write('apps/app1/src/environments/environment.prod.ts', '');
const project = readProjectConfiguration(tree, 'app1');
project.targets.build.configurations.production.fileReplacements = [
{
replace: 'apps/app1/src/environments/environment.ts',
with: 'apps/app1/src/environments/environment.prod.ts',
},
];
updateProjectConfiguration(tree, 'app1', project);
// ACT
await setupSsr(tree, { project: 'app1' });
// ASSERT
expect(
readProjectConfiguration(tree, 'app1').targets.server
).toMatchSnapshot();
});
});
@@ -1,5 +1,5 @@
import { readFileSync, writeFileSync } from 'fs-extra';
import { detectPackageManager, PackageManager } from '../package-manager';
import { detectPackageManager, PackageManager } from '../utils/package-manager';
import {
parseYarnLockFile,
pruneYarnLockFile,
@@ -19,13 +19,13 @@ import {
transitiveDependencyPnpmLookup,
} from './pnpm';
import { LockFileData } from './lock-file-type';
import { workspaceRoot } from '../workspace-root';
import { workspaceRoot } from '../utils/workspace-root';
import { join } from 'path';
import { hashExternalNodes, hashString, mapExternalNodes } from './utils';
import {
ProjectGraph,
ProjectGraphExternalNode,
} from '../../config/project-graph';
} from '../config/project-graph';
import { existsSync } from 'fs';
const YARN_LOCK_PATH = join(workspaceRoot, 'yarn.lock');
@@ -15,7 +15,6 @@ import {
lockFileV2YargsAndDevkitOnly,
} from './__fixtures__/npm.lock';
import { vol } from 'memfs';
import { readJsonFile } from '../fileutils';
jest.mock('fs', () => require('memfs').fs);
@@ -1,9 +1,9 @@
import { existsSync } from 'fs';
import { satisfies } from 'semver';
import { readJsonFile } from '../fileutils';
import { output } from '../output';
import { joinPathFragments } from '../path';
import { workspaceRoot } from '../workspace-root';
import { readJsonFile } from '../utils/fileutils';
import { output } from '../utils/output';
import { joinPathFragments } from '../utils/path';
import { workspaceRoot } from '../utils/workspace-root';
import { LockFileData, PackageDependency } from './lock-file-type';
import {
sortObject,
@@ -1,15 +1,15 @@
import { defaultHashing } from '../../hasher/hashing-impl';
import { defaultHashing } from '../hasher/hashing-impl';
import {
LockFileData,
PackageDependency,
PackageVersions,
} from './lock-file-type';
import { workspaceRoot } from '../workspace-root';
import { workspaceRoot } from '../utils/workspace-root';
import { existsSync, readFileSync } from 'fs';
import {
ProjectGraph,
ProjectGraphExternalNode,
} from '../../config/project-graph';
} from '../config/project-graph';
/**
* Simple sort function to ensure keys are ordered alphabetically
@@ -25,7 +25,6 @@ import { getRootTsConfigPath } from '../utils/typescript';
import {
ProjectFileMap,
ProjectGraph,
ProjectGraphExternalNode,
ProjectGraphProcessorContext,
} from '../config/project-graph';
import { readJsonFile } from '../utils/fileutils';
@@ -45,7 +44,7 @@ import {
lockFileHash,
mapLockFileDataToPartialGraph,
parseLockFile,
} from '../utils/lock-file/lock-file';
} from '../lock-file/lock-file';
export async function buildProjectGraph() {
const projectConfigurations = readAllWorkspaceConfiguration();
+41 -2
View File
@@ -1460,7 +1460,7 @@ describe('params', () => {
]);
});
it('should use an multiselect prompt for x-prompts with items', () => {
it('should use a multiselect prompt for x-prompts with items', () => {
const prompts = getPromptsForSchema(
{},
{
@@ -1492,7 +1492,46 @@ describe('params', () => {
]);
});
it('should use an multiselect prompt for x-prompts with items', () => {
it('should use a multiselect prompt for array properties', () => {
const prompts = getPromptsForSchema(
{},
{
properties: {
pets: {
type: 'array',
'x-prompt': {
type: 'list',
message: 'What kind of pets do you have?',
items: [
{ label: 'Cat', value: 'cat' },
{ label: 'Dog', value: 'dog' },
{ label: 'Fish', value: 'fish' },
],
},
},
},
},
{
version: 2,
projects: {},
}
);
expect(prompts).toEqual([
{
type: 'multiselect',
name: 'pets',
message: 'What kind of pets do you have?',
choices: [
{ message: 'Cat', name: 'cat' },
{ message: 'Dog', name: 'dog' },
{ message: 'Fish', name: 'fish' },
],
},
]);
});
it('should use a multiselect prompt for x-prompts with items', () => {
const prompts = getPromptsForSchema(
{},
{
+4 -3
View File
@@ -770,9 +770,10 @@ export function getPromptsForSchema(
question.type = 'confirm';
} else if (v['x-prompt'].items) {
question.message = v['x-prompt'].message;
question.type = v['x-prompt'].multiselect
? 'multiselect'
: 'autocomplete';
question.type =
v['x-prompt'].multiselect || v.type === 'array'
? 'multiselect'
: 'autocomplete';
question.choices =
v['x-prompt'].items &&
v['x-prompt'].items.map((item) => {
@@ -1,5 +1,7 @@
// source: https://github.com/Myrmod/vitejs-theming/blob/master/build-plugins/rollup/replace-files.js
import { resolve } from 'path';
/**
* @function replaceFiles
* @param {FileReplacement[]} replacements
@@ -12,10 +14,21 @@ export default function replaceFiles(replacements: FileReplacement[]) {
return {
name: 'rollup-plugin-replace-files',
enforce: 'pre',
async resolveId(source, importer) {
const resolved = await this.resolve(source, importer, { skipSelf: true });
const foundReplace = replacements.find(
(replacement) => replacement.replace === resolved?.id
async resolveId(source, importer, options) {
const resolved = await this.resolve(source, importer, {
...options,
skipSelf: true,
});
/**
* The reason we're using endsWith here is because the resolved id
* will be the absolute path to the file. We want to check if the
* file ends with the file we're trying to replace, which will be essentially
* the path from the root of our workspace.
*/
const foundReplace = replacements.find((replacement) =>
resolved?.id?.endsWith(replacement.replace)
);
if (foundReplace) {
console.info(
@@ -36,14 +36,6 @@ function checkDependenciesInstalled(host: Tree, schema: Schema) {
devDependencies['@vitejs/plugin-react'] = vitePluginReactVersion;
}
if (schema.uiFramework === 'vue3') {
devDependencies['@vitejs/plugin-vue'] = vitePluginReactVersion;
}
if (schema.uiFramework === 'vue3-jsx') {
devDependencies['@vitejs/plugin-vue-jsx'] = vitePluginReactVersion;
}
return addDependenciesToPackageJson(host, dependencies, devDependencies);
}
+1 -1
View File
@@ -1,3 +1,3 @@
export interface Schema {
uiFramework: 'react' | 'vue3' | 'vue3-jsx';
uiFramework: 'react' | 'none';
}
@@ -8,7 +8,7 @@
"uiFramework": {
"type": "string",
"description": "UI Framework to use for Vite.",
"enum": ["react", "vue3", "vue3-jsx"],
"enum": ["react", "none"],
"default": "react",
"x-prompt": "What UI framework plugin should Vite use?"
}
+1 -3
View File
@@ -41,6 +41,7 @@ export async function getBuildConfig(
context.root,
projectRoot
),
plugins: [replaceFiles(options.fileReplacements)],
build: getViteBuildOptions(
options as ViteDevServerExecutorOptions & ViteBuildExecutorOptions,
projectRoot
@@ -144,9 +145,6 @@ export function getViteBuildOptions(
commonjsOptions: {
transformMixedEsModules: true,
},
rollupOptions: {
plugins: [replaceFiles(options.fileReplacements)],
},
};
buildOptions = {
-196
View File
@@ -1,196 +0,0 @@
/*
* This script checks if new versions of node modules are available.
* It uses naming conventions to transform constants to matching node module name.
*
* Usage:
* yarn check-versions [file|package]
*
* Positional arg:
* - [file]: relative or absolute file path to the versions file.
*
* Example:
* yarn check-versions react
*/
import { join, relative } from 'path';
import { gt } from 'semver';
import { readJsonSync, writeJsonSync } from 'fs-extra';
import * as chalk from 'chalk';
import { dasherize } from '../packages/workspace/src/utils/strings';
import * as glob from 'glob';
import { execSync } from 'child_process';
import { readFileSync, writeFileSync } from 'fs';
const root = join(__dirname, '..');
const excluded = ['nxVersion'];
const scoped = [
'babel',
'emotion',
'reduxjs',
'swc',
'testing-library',
'types',
];
try {
const files = process.argv[2]
? [normalize(process.argv[2])]
: glob.sync('packages/**/*/versions.ts').map((x) => relative(root, x));
checkFiles(files);
} catch (e) {
console.log(chalk.red(e.message));
process.exitCode = 1;
}
function normalize(x: string) {
if (x.endsWith('.ts')) {
return x;
} else {
return join('packages', x, 'src/utils/versions.ts');
}
}
// -----------------------------------------------------------------------------
function checkFiles(files: string[]) {
console.log(chalk.blue(`Checking versions in the following files...\n`));
console.log(` - ${files.join('\n - ')}\n`);
const maxFileNameLength = Math.max(...files.map((f) => f.length));
let hasError = false;
files.forEach((f) => {
const projectRoot = f.split('/src/')[0];
const migrationsPath = join(projectRoot, 'migrations.json');
const migrationsJson = readJsonSync(migrationsPath);
let versionsContent = readFileSync(f).toString();
const versions = getVersions(f);
const npmPackages = getPackages(versions);
const results = npmPackages.map(([p, v, o]) => getVersionData(p, v, o));
const logContext = `${f.padEnd(maxFileNameLength)}`;
const packageUpdates = {};
results.forEach((r) => {
if (r.outdated) {
console.log(
`${logContext}${chalk.bold(
r.package
)} has new version ${chalk.bold(r.latest)} (current: ${r.prev})`
);
versionsContent = versionsContent.replace(
`${r.variable} = '${r.prev}'`,
`${r.variable} = '${r.latest}'`
);
packageUpdates[r.package] = {
version: r.latest,
alwaysAddToPackageJson: false,
};
}
if (r.invalid) {
hasError = true;
console.log(
`${logContext} ⚠️ ${chalk.bold(r.package)} has an invalid version (${
r.prev
}) specified. Latest is ${r.latest}.`
);
}
});
if (Object.keys(packageUpdates).length > 0) {
migrationsJson.packageJsonUpdates['x.y.z'] = {
version: 'x.y.z',
packages: packageUpdates,
};
writeFileSync(f, versionsContent);
writeJsonSync(migrationsPath, migrationsJson, { spaces: 2 });
}
});
if (hasError) {
throw new Error('Invalid versions of packages found (please see above).');
}
}
function getVersions(path: string) {
const versionsPath =
path.startsWith('.') || path.startsWith('packages')
? join(__dirname, '..', path)
: path;
try {
return require(versionsPath);
} catch {
throw new Error(`Could not load ${path}. Please make sure it is valid.`);
}
}
function getPackages(versions: Record<string, string>): string[][] {
return Object.entries(versions).reduce((acc, [name, version]) => {
if (!excluded.includes(name)) {
const npmName = getNpmName(name);
acc.push([npmName, version, name]);
}
return acc;
}, [] as string[][]);
}
function getNpmName(name: string): string {
const dashedName = dasherize(name.replace(/Version$/, ''));
const scope = scoped.find((s) => dashedName.startsWith(`${s}-`));
if (scope) {
const rest = dashedName.split(`${scope}-`)[1];
return `@${scope}/${rest}`;
} else {
return dashedName;
}
}
function getVersionData(
p: string,
v: string,
o: string
): {
variable: string;
package: string;
outdated: boolean;
invalid: boolean;
latest: string;
prev?: string;
} {
try {
const latest = JSON.parse(
execSync(`npm view ${p} version --json --silent`, {
stdio: ['ignore'],
}).toString('utf-8')
);
if (gt(latest, v)) {
return {
variable: o,
package: p,
outdated: true,
invalid: false,
latest,
prev: v,
};
}
if (gt(v, latest)) {
return {
variable: o,
package: p,
outdated: false,
invalid: true,
latest,
prev: v,
};
}
} catch {
// ignored
}
return {
variable: o,
package: p,
outdated: false,
invalid: false,
latest: v,
};
}