Skip to content

Commit

Permalink
feat(remix): add option to create-nx-workspace (nrwl#22334)
Browse files Browse the repository at this point in the history
  • Loading branch information
Coly010 authored and arekkubaczkowski committed Mar 19, 2024
1 parent ee06416 commit 1c8bd2b
Show file tree
Hide file tree
Showing 12 changed files with 271 additions and 11 deletions.
2 changes: 1 addition & 1 deletion docs/generated/cli/create-nx-workspace.md
Expand Up @@ -145,7 +145,7 @@ Prefix to use for Angular component and directive selectors.

Type: `string`

Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "vue-monorepo", "vue-standalone", "nuxt", "nuxt-standalone", "next", "nextjs-standalone", "react-native", "expo", "nest", "express", "react", "vue", "angular", "node-standalone", "node-monorepo", "ts-standalone"]. To build your own see https://nx.dev/extending-nx/recipes/create-preset
Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "vue-monorepo", "vue-standalone", "nuxt", "nuxt-standalone", "next", "nextjs-standalone", "remix-monorepo", "remix-standalone", "react-native", "expo", "nest", "express", "react", "vue", "angular", "node-standalone", "node-monorepo", "ts-standalone"]. To build your own see https://nx.dev/extending-nx/recipes/create-preset

### routing

Expand Down
Expand Up @@ -145,7 +145,7 @@ Prefix to use for Angular component and directive selectors.

Type: `string`

Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "vue-monorepo", "vue-standalone", "nuxt", "nuxt-standalone", "next", "nextjs-standalone", "react-native", "expo", "nest", "express", "react", "vue", "angular", "node-standalone", "node-monorepo", "ts-standalone"]. To build your own see https://nx.dev/extending-nx/recipes/create-preset
Customizes the initial content of your workspace. Default presets include: ["apps", "empty", "core", "npm", "ts", "web-components", "angular-monorepo", "angular-standalone", "react-monorepo", "react-standalone", "vue-monorepo", "vue-standalone", "nuxt", "nuxt-standalone", "next", "nextjs-standalone", "remix-monorepo", "remix-standalone", "react-native", "expo", "nest", "express", "react", "vue", "angular", "node-standalone", "node-monorepo", "ts-standalone"]. To build your own see https://nx.dev/extending-nx/recipes/create-preset

### routing

Expand Down
26 changes: 22 additions & 4 deletions packages/create-nx-workspace/bin/create-nx-workspace.ts
Expand Up @@ -43,7 +43,7 @@ interface ReactArguments extends BaseArguments {
stack: 'react';
workspaceType: 'standalone' | 'integrated';
appName: string;
framework: 'none' | 'next';
framework: 'none' | 'next' | 'remix';
style: string;
bundler: 'webpack' | 'vite' | 'rspack';
nextAppDir: boolean;
Expand Down Expand Up @@ -378,6 +378,8 @@ async function determineStack(
case Preset.ReactMonorepo:
case Preset.NextJs:
case Preset.NextJsStandalone:
case Preset.RemixStandalone:
case Preset.RemixMonorepo:
return 'react';
case Preset.Vue:
case Preset.VueStandalone:
Expand Down Expand Up @@ -520,7 +522,8 @@ async function determineReactOptions(
preset = parsedArgs.preset;
if (
preset === Preset.ReactStandalone ||
preset === Preset.NextJsStandalone
preset === Preset.NextJsStandalone ||
preset === Preset.RemixStandalone
) {
appName = parsedArgs.appName ?? parsedArgs.name;
} else {
Expand Down Expand Up @@ -548,6 +551,12 @@ async function determineReactOptions(
} else {
preset = Preset.NextJs;
}
} else if (framework === 'remix') {
if (workspaceType === 'standalone') {
preset = Preset.RemixStandalone;
} else {
preset = Preset.RemixMonorepo;
}
} else if (framework === 'react-native') {
preset = Preset.ReactNative;
} else if (framework === 'expo') {
Expand All @@ -568,6 +577,11 @@ async function determineReactOptions(
nextAppDir = await determineNextAppDir(parsedArgs);
nextSrcDir = await determineNextSrcDir(parsedArgs);
e2eTestRunner = await determineE2eTestRunner(parsedArgs);
} else if (
preset === Preset.RemixMonorepo ||
preset === Preset.RemixStandalone
) {
e2eTestRunner = await determineE2eTestRunner(parsedArgs);
}

if (parsedArgs.style) {
Expand Down Expand Up @@ -1017,9 +1031,9 @@ async function determineAppName(

async function determineReactFramework(
parsedArgs: yargs.Arguments<ReactArguments>
): Promise<'none' | 'nextjs' | 'expo' | 'react-native'> {
): Promise<'none' | 'nextjs' | 'remix' | 'expo' | 'react-native'> {
const reply = await enquirer.prompt<{
framework: 'none' | 'nextjs' | 'expo' | 'react-native';
framework: 'none' | 'nextjs' | 'remix' | 'expo' | 'react-native';
}>([
{
name: 'framework',
Expand All @@ -1035,6 +1049,10 @@ async function determineReactFramework(
name: 'nextjs',
message: 'Next.js [ https://nextjs.org/ ]',
},
{
name: 'remix',
message: 'Remix [ https://remix.run/ ]',
},
{
name: 'expo',
message: 'Expo [ https://expo.io/ ]',
Expand Down
2 changes: 2 additions & 0 deletions packages/create-nx-workspace/src/utils/preset/preset.ts
Expand Up @@ -15,6 +15,8 @@ export enum Preset {
NuxtStandalone = 'nuxt-standalone',
NextJs = 'next',
NextJsStandalone = 'nextjs-standalone',
RemixMonorepo = 'remix-monorepo',
RemixStandalone = 'remix-standalone',
ReactNative = 'react-native',
Expo = 'expo',
Nest = 'nest',
Expand Down
Expand Up @@ -1147,8 +1147,7 @@ export default {
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
coverageDirectory: './coverage/test',
testMatch: [
'<rootDir>/src/**/__tests__/**/*.[jt]s?(x)',
'<rootDir>/src/**/*(*.)@(spec|test).[jt]s?(x)',
'<rootDir>/tests/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}',
],
};
"
Expand Down
23 changes: 23 additions & 0 deletions packages/remix/src/generators/application/application.impl.ts
Expand Up @@ -35,6 +35,7 @@ import initGenerator from '../init/init';
import { initGenerator as jsInitGenerator } from '@nx/js';
import { addBuildTargetDefaults } from '@nx/devkit/src/generators/add-build-target-defaults';
import { logShowProjectCommand } from '@nx/devkit/src/utils/log-show-project-command';
import { updateJestTestMatch } from '../../utils/testing-config-utils';

export function remixApplicationGenerator(
tree: Tree,
Expand Down Expand Up @@ -267,6 +268,28 @@ export async function remixApplicationGeneratorInternal(
extractTsConfigBase(tree);
}

if (options.rootProject) {
updateJson(tree, `package.json`, (json) => {
json.type = 'module';
return json;
});

if (options.unitTestRunner === 'jest') {
tree.write(
'jest.preset.js',
`import { nxPreset } from '@nx/jest/preset/jest-preset.js';
export default {...nxPreset};
`
);

updateJestTestMatch(
tree,
'jest.config.ts',
'<rootDir>/tests/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'
);
}
}

tasks.push(await addE2E(tree, options));

if (!options.skipFormat) {
Expand Down
27 changes: 27 additions & 0 deletions packages/remix/src/utils/testing-config-utils.ts
Expand Up @@ -100,6 +100,33 @@ export function updateJestTestSetup(
}
}

export function updateJestTestMatch(
tree: Tree,
pathToJestConfig: string,
includesString: string
) {
if (!tsModule) {
tsModule = ensureTypescript();
}
const { tsquery } = require('@phenomnomnominal/tsquery');
const fileContents = tree.read(pathToJestConfig, 'utf-8');

const ast = tsquery.ast(fileContents);

const TEST_MATCH_SELECTOR =
'PropertyAssignment:has(Identifier[name=testMatch])';
const nodes = tsquery(ast, TEST_MATCH_SELECTOR, { visitAllChildren: true });

if (nodes.length !== 0) {
const updatedFileContents = stripIndents`${fileContents.slice(
0,
nodes[0].getStart()
)}testMatch: ["${includesString}"]${fileContents.slice(nodes[0].getEnd())}`;

tree.write(pathToJestConfig, updatedFileContents);
}
}

export function updateVitestTestIncludes(
tree: Tree,
pathToVitestConfig: string,
Expand Down
Expand Up @@ -1286,6 +1286,166 @@ It will show tasks that you can run with Nx.
"
`;

exports[`@nx/workspace:generateWorkspaceFiles README.md should be created for RemixMonorepo preset 1`] = `
"# Proj

<a alt="Nx logo" href="https://nx.dev" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-logo.png" width="45"></a>

✨ **This workspace has been generated by [Nx, Smart Monorepos · Fast CI.](https://nx.dev)** ✨

## Integrate with editors

Enhance your Nx experience by installing [Nx Console](https://nx.dev/nx-console) for your favorite editor. Nx Console
provides an interactive UI to view your projects, run tasks, generate code, and more! Available for VSCode, IntelliJ and
comes with a LSP for Vim users.

## Nx plugins and code generators

Add Nx plugins to leverage their code generators and automated, inferred tasks.

\`\`\`
# Add plugin
npx nx add @nx/react

# Use code generator
npx nx generate @nx/react:app demo

# Run development server
npx nx serve demo

# View project details
npx nx show project demo --web
\`\`\`

Run \`npx nx list\` to get a list of available plugins and whether they have generators. Then run \`npx nx list <plugin-name>\` to see what generators are available.

Learn more about [code generators](https://nx.dev/features/generate-code) and [inferred tasks](https://nx.dev/concepts/inferred-tasks) in the docs.

## Running tasks

To execute tasks with Nx use the following syntax:

\`\`\`
npx nx <target> <project> <...options>
\`\`\`

You can also run multiple targets:

\`\`\`
npx nx run-many -t <target1> <target2>
\`\`\`

..or add \`-p\` to filter specific projects

\`\`\`
npx nx run-many -t <target1> <target2> -p <proj1> <proj2>
\`\`\`

Targets can be defined in the \`package.json\` or \`projects.json\`. Learn more [in the docs](https://nx.dev/features/run-tasks).

## Set up CI!

Nx comes with local caching already built-in (check your \`nx.json\`). On CI you might want to go a step further.

- [Set up remote caching](https://nx.dev/features/share-your-cache)
- [Set up task distribution across multiple machines](https://nx.dev/nx-cloud/features/distribute-task-execution)
- [Learn more how to setup CI](https://nx.dev/recipes/ci)

## Explore the project graph

Run \`npx nx graph\` to show the graph of the workspace.
It will show tasks that you can run with Nx.

- [Learn more about Exploring the Project Graph](https://nx.dev/core-features/explore-graph)

## Connect with us!

- [Join the community](https://nx.dev/community)
- [Subscribe to the Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Follow us on Twitter](https://twitter.com/nxdevtools)
"
`;

exports[`@nx/workspace:generateWorkspaceFiles README.md should be created for RemixStandalone preset 1`] = `
"# Proj

<a alt="Nx logo" href="https://nx.dev" target="_blank" rel="noreferrer"><img src="https://raw.githubusercontent.com/nrwl/nx/master/images/nx-logo.png" width="45"></a>

✨ **This workspace has been generated by [Nx, Smart Monorepos · Fast CI.](https://nx.dev)** ✨

## Integrate with editors

Enhance your Nx experience by installing [Nx Console](https://nx.dev/nx-console) for your favorite editor. Nx Console
provides an interactive UI to view your projects, run tasks, generate code, and more! Available for VSCode, IntelliJ and
comes with a LSP for Vim users.

## Nx plugins and code generators

Add Nx plugins to leverage their code generators and automated, inferred tasks.

\`\`\`
# Add plugin
npx nx add @nx/react

# Use code generator
npx nx generate @nx/react:app demo

# Run development server
npx nx serve demo

# View project details
npx nx show project demo --web
\`\`\`

Run \`npx nx list\` to get a list of available plugins and whether they have generators. Then run \`npx nx list <plugin-name>\` to see what generators are available.

Learn more about [code generators](https://nx.dev/features/generate-code) and [inferred tasks](https://nx.dev/concepts/inferred-tasks) in the docs.

## Running tasks

To execute tasks with Nx use the following syntax:

\`\`\`
npx nx <target> <project> <...options>
\`\`\`

You can also run multiple targets:

\`\`\`
npx nx run-many -t <target1> <target2>
\`\`\`

..or add \`-p\` to filter specific projects

\`\`\`
npx nx run-many -t <target1> <target2> -p <proj1> <proj2>
\`\`\`

Targets can be defined in the \`package.json\` or \`projects.json\`. Learn more [in the docs](https://nx.dev/features/run-tasks).

## Set up CI!

Nx comes with local caching already built-in (check your \`nx.json\`). On CI you might want to go a step further.

- [Set up remote caching](https://nx.dev/features/share-your-cache)
- [Set up task distribution across multiple machines](https://nx.dev/nx-cloud/features/distribute-task-execution)
- [Learn more how to setup CI](https://nx.dev/recipes/ci)

## Explore the project graph

Run \`npx nx graph\` to show the graph of the workspace.
It will show tasks that you can run with Nx.

- [Learn more about Exploring the Project Graph](https://nx.dev/core-features/explore-graph)

## Connect with us!

- [Join the community](https://nx.dev/community)
- [Subscribe to the Nx Youtube Channel](https://www.youtube.com/@nxdevtools)
- [Follow us on Twitter](https://twitter.com/nxdevtools)
"
`;

exports[`@nx/workspace:generateWorkspaceFiles README.md should be created for TS preset 1`] = `
"# Proj

Expand Down
4 changes: 4 additions & 0 deletions packages/workspace/src/generators/new/generate-preset.ts
Expand Up @@ -122,6 +122,10 @@ function getPresetDependencies({
case Preset.NextJsStandalone:
return { dependencies: { '@nx/next': nxVersion }, dev: {} };

case Preset.RemixStandalone:
case Preset.RemixMonorepo:
return { dependencies: { '@nx/remix': nxVersion }, dev: {} };

case Preset.VueMonorepo:
case Preset.VueStandalone:
return {
Expand Down
Expand Up @@ -107,6 +107,7 @@ function createFiles(tree: Tree, options: NormalizedSchema) {
options.preset === Preset.NuxtStandalone ||
options.preset === Preset.NodeStandalone ||
options.preset === Preset.NextJsStandalone ||
options.preset === Preset.RemixStandalone ||
options.preset === Preset.TsStandalone
? './files-root-app'
: options.preset === Preset.NPM
Expand Down

0 comments on commit 1c8bd2b

Please sign in to comment.