Skip to content

Commit

Permalink
feat(nextjs): update to Next.js 13.3.0 (#16130)
Browse files Browse the repository at this point in the history
  • Loading branch information
jaysoo authored Apr 12, 2023
1 parent 393434e commit 0578116
Show file tree
Hide file tree
Showing 13 changed files with 206 additions and 77 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ describe('create-nx-workspace --preset=npm', () => {
const tsconfig = readJson(`tsconfig.base.json`);
expect(tsconfig.compilerOptions.paths).toEqual({
[libName]: [`packages/${libName}/src/index.ts`],
[`${libName}/server`]: [`packages/${libName}/src/server.ts`],
});
});

Expand Down
7 changes: 5 additions & 2 deletions packages/angular/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@ import {
formatFiles,
GeneratorCallback,
installPackagesTask,
joinPathFragments,
removeDependenciesFromPackageJson,
Tree,
} from '@nrwl/devkit';
import { jestProjectGenerator } from '@nrwl/jest';
import { Linter } from '@nrwl/linter';
import { updateRootTsConfig } from '@nrwl/js';
import { addTsConfigPath } from '@nrwl/js';
import { lt } from 'semver';
import init from '../../generators/init/init';
import { E2eTestRunner } from '../../utils/test-runners';
Expand Down Expand Up @@ -107,7 +108,9 @@ export async function libraryGenerator(
addBuildableLibrariesPostCssDependencies(tree);
}

updateRootTsConfig(tree, { ...libraryOptions, js: false });
addTsConfigPath(tree, libraryOptions.importPath, [
joinPathFragments(libraryOptions.projectRoot, './src', 'index.ts'),
]);

if (!libraryOptions.skipFormat) {
await formatFiles(tree);
Expand Down
10 changes: 8 additions & 2 deletions packages/expo/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
updateJson,
} from '@nrwl/devkit';

import { updateRootTsConfig } from '@nrwl/js';
import { addTsConfigPath } from '@nrwl/js';

import init from '../init/init';
import { addLinting } from '../../utils/add-linting';
Expand Down Expand Up @@ -54,7 +54,13 @@ export async function expoLibraryGenerator(
);

if (!options.skipTsConfig) {
updateRootTsConfig(host, options);
addTsConfigPath(host, options.importPath, [
joinPathFragments(
options.projectRoot,
'./src',
'index.' + (options.js ? 'js' : 'ts')
),
]);
}

const jestTask = await addJest(
Expand Down
10 changes: 8 additions & 2 deletions packages/js/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import {
import { getImportPath } from 'nx/src/utils/path';

import {
addTsConfigPath,
getRelativePathToRootTsConfig,
updateRootTsConfig,
} from '../../utils/typescript/ts-config';
import { join } from 'path';
import { addMinimalPublishScript } from '../../utils/minimal-publish-script';
Expand Down Expand Up @@ -117,7 +117,13 @@ export async function projectGenerator(
}

if (!schema.skipTsConfig) {
updateRootTsConfig(tree, options);
addTsConfigPath(tree, options.importPath, [
joinPathFragments(
options.projectRoot,
'./src',
'index.' + (options.js ? 'js' : 'ts')
),
]);
}

if (!options.skipFormat) {
Expand Down
34 changes: 9 additions & 25 deletions packages/js/src/utils/typescript/ts-config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,38 +52,22 @@ export function getRootTsConfigFileName(tree: Tree): string | null {
return null;
}

export function updateRootTsConfig(
host: Tree,
options: {
name: string;
importPath?: string;
projectRoot: string;
js?: boolean;
}
export function addTsConfigPath(
tree: Tree,
importPath: string,
lookupPaths: string[]
) {
if (!options.importPath) {
throw new Error(
`Unable to update ${options.name} using the import path "${options.importPath}". Make sure to specify a valid import path one.`
);
}
updateJson(host, getRootTsConfigPathInTree(host), (json) => {
updateJson(tree, getRootTsConfigPathInTree(tree), (json) => {
const c = json.compilerOptions;
c.paths = c.paths || {};
delete c.paths[options.name];
c.paths ??= {};

if (c.paths[options.importPath]) {
if (c.paths[importPath]) {
throw new Error(
`You already have a library using the import path "${options.importPath}". Make sure to specify a unique one.`
`You already have a library using the import path "${importPath}". Make sure to specify a unique one.`
);
}

c.paths[options.importPath] = [
joinPathFragments(
options.projectRoot,
'./src',
'index.' + (options.js ? 'js' : 'ts')
),
];
c.paths[importPath] = lookupPaths;

return json;
});
Expand Down
26 changes: 26 additions & 0 deletions packages/next/src/generators/library/lib/normalize-options.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { Tree } from '@nrwl/devkit';
import { Linter } from '@nrwl/linter';
import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { normalizeOptions } from './normalize-options';

describe('normalizeOptions', () => {
let tree: Tree;

beforeEach(() => {
tree = createTreeWithEmptyWorkspace();
});

it('should set importPath and projectRoot', () => {
const options = normalizeOptions(tree, {
name: 'my-lib',
style: 'css',
linter: Linter.None,
unitTestRunner: 'jest',
});

expect(options).toMatchObject({
importPath: '@proj/my-lib',
projectRoot: 'my-lib',
});
});
});
32 changes: 32 additions & 0 deletions packages/next/src/generators/library/lib/normalize-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {
getImportPath,
getWorkspaceLayout,
joinPathFragments,
names,
Tree,
} from '@nrwl/devkit';
import { Schema } from '../schema';

export interface NormalizedSchema extends Schema {
importPath: string;
projectRoot: string;
}

export function normalizeOptions(
host: Tree,
options: Schema
): NormalizedSchema {
const name = names(options.name).fileName;
const projectDirectory = options.directory
? `${names(options.directory).fileName}/${name}`
: name;

const { libsDir } = getWorkspaceLayout(host);
const projectRoot = joinPathFragments(libsDir, projectDirectory);
const { npmScope } = getWorkspaceLayout(host);
return {
...options,
importPath: options.importPath ?? getImportPath(npmScope, projectDirectory),
projectRoot,
};
}
29 changes: 29 additions & 0 deletions packages/next/src/generators/library/library.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ import { createTreeWithEmptyWorkspace } from '@nrwl/devkit/testing';
import { Linter } from '@nrwl/linter';
import libraryGenerator from './library';
import { Schema } from './schema';

// need to mock cypress otherwise it'll use the nx installed version from package.json
// which is v9 while we are testing for the new v10 version
jest.mock('@nrwl/cypress/src/utils/cypress-version');

describe('next library', () => {
let mockedInstalledCypressVersion: jest.Mock<
ReturnType<typeof installedCypressVersion>
Expand Down Expand Up @@ -133,4 +135,31 @@ describe('next library', () => {
.jsxImportSource
).toEqual('@emotion/react');
});

it('should generate a server-only entry point', async () => {
const appTree = createTreeWithEmptyWorkspace();

await libraryGenerator(appTree, {
name: 'myLib',
linter: Linter.EsLint,
skipFormat: false,
skipTsConfig: false,
unitTestRunner: 'jest',
style: 'css',
component: true,
});

expect(appTree.read('my-lib/src/index.ts', 'utf-8')).toContain(
'React client components'
);
expect(appTree.read('my-lib/src/server.ts', 'utf-8')).toContain(
'React server components'
);
expect(
readJson(appTree, 'tsconfig.base.json').compilerOptions.paths
).toMatchObject({
'@proj/my-lib': ['my-lib/src/index.ts'],
'@proj/my-lib/server': ['my-lib/src/server.ts'],
});
});
});
107 changes: 70 additions & 37 deletions packages/next/src/generators/library/library.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import {
convertNxGenerator,
formatFiles,
GeneratorCallback,
getImportPath,
getWorkspaceLayout,
joinPathFragments,
names,
Expand All @@ -10,19 +11,15 @@ import {
updateJson,
} from '@nrwl/devkit';
import { libraryGenerator as reactLibraryGenerator } from '@nrwl/react/src/generators/library/library';
import { addTsConfigPath } from '@nrwl/js';

import { nextInitGenerator } from '../init/init';
import { Schema } from './schema';
import { normalizeOptions } from './lib/normalize-options';

export async function libraryGenerator(host: Tree, options: Schema) {
const name = names(options.name).fileName;
export async function libraryGenerator(host: Tree, rawOptions: Schema) {
const options = normalizeOptions(host, rawOptions);
const tasks: GeneratorCallback[] = [];
const projectDirectory = options.directory
? `${names(options.directory).fileName}/${name}`
: name;

const { libsDir } = getWorkspaceLayout(host);
const projectRoot = joinPathFragments(libsDir, projectDirectory);
const initTask = await nextInitGenerator(host, {
...options,
skipFormat: true,
Expand All @@ -36,42 +33,78 @@ export async function libraryGenerator(host: Tree, options: Schema) {
});
tasks.push(libTask);

updateJson(host, joinPathFragments(projectRoot, '.babelrc'), (json) => {
if (options.style === '@emotion/styled') {
json.presets = [
[
'@nrwl/next/babel',
{
'preset-react': {
runtime: 'automatic',
importSource: '@emotion/react',
const indexPath = joinPathFragments(
options.projectRoot,
'src',
`index.${options.js ? 'js' : 'ts'}`
);
const indexContent = host.read(indexPath, 'utf-8');
host.write(
indexPath,
`// Use this file to export React client components (e.g. those with 'use client' directive) or other non-server utilities\n${indexContent}`
);
// Additional entry for Next.js libraries so React Server Components are exported from a separate entry point.
// This is needed because RSC exported from `src/index.ts` will mark the entire file as server-only and throw an error when used from a client component.
// See: https://github.com/nrwl/nx/issues/15830
const serverEntryPath = joinPathFragments(
options.projectRoot,
'./src',
'server.' + (options.js ? 'js' : 'ts')
);
host.write(
joinPathFragments(
options.projectRoot,
'src',
`server.${options.js ? 'js' : 'ts'}`
),
`// Use this file to export React server components\n`
);
addTsConfigPath(host, `${options.importPath}/server`, [serverEntryPath]);

updateJson(
host,
joinPathFragments(options.projectRoot, '.babelrc'),
(json) => {
if (options.style === '@emotion/styled') {
json.presets = [
[
'@nrwl/next/babel',
{
'preset-react': {
runtime: 'automatic',
importSource: '@emotion/react',
},
},
},
],
];
} else if (options.style === 'styled-jsx') {
// next.js doesn't require the `styled-jsx/babel' plugin as it is already
// built-into the `next/babel` preset
json.presets = ['@nrwl/next/babel'];
json.plugins = (json.plugins || []).filter(
(x) => x !== 'styled-jsx/babel'
);
} else {
json.presets = ['@nrwl/next/babel'];
],
];
} else if (options.style === 'styled-jsx') {
// next.js doesn't require the `styled-jsx/babel' plugin as it is already
// built-into the `next/babel` preset
json.presets = ['@nrwl/next/babel'];
json.plugins = (json.plugins || []).filter(
(x) => x !== 'styled-jsx/babel'
);
} else {
json.presets = ['@nrwl/next/babel'];
}
return json;
}
return json;
});
);

updateJson(host, joinPathFragments(projectRoot, 'tsconfig.json'), (json) => {
if (options.style === '@emotion/styled') {
json.compilerOptions.jsxImportSource = '@emotion/react';
updateJson(
host,
joinPathFragments(options.projectRoot, 'tsconfig.json'),
(json) => {
if (options.style === '@emotion/styled') {
json.compilerOptions.jsxImportSource = '@emotion/react';
}
return json;
}
return json;
});
);

updateJson(
host,
joinPathFragments(projectRoot, 'tsconfig.lib.json'),
joinPathFragments(options.projectRoot, 'tsconfig.lib.json'),
(json) => {
if (!json.files) {
json.files = [];
Expand Down
4 changes: 2 additions & 2 deletions packages/next/src/generators/library/schema.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ export interface Schema {
name: string;
directory?: string;
style: SupportedStyles;
skipTsConfig: boolean;
skipFormat: boolean;
skipTsConfig?: boolean;
skipFormat?: boolean;
tags?: string;
pascalCaseFiles?: boolean;
routing?: boolean;
Expand Down
6 changes: 3 additions & 3 deletions packages/next/src/utils/versions.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
export const nxVersion = require('../../package.json').version;

export const nextVersion = '13.1.1';
export const eslintConfigNextVersion = '13.1.1';
export const sassVersion = '1.55.0';
export const nextVersion = '13.3.0';
export const eslintConfigNextVersion = '13.3.0';
export const sassVersion = '1.61.0';
export const lessLoader = '11.1.0';
export const stylusLoader = '7.1.0';
export const emotionServerVersion = '11.10.0';
Expand Down
Loading

0 comments on commit 0578116

Please sign in to comment.