UNPKG

@nx/remix

Version:

The Remix plugin for Nx contains executors and generators for managing Remix applications and libraries within an Nx workspace. It provides: - Integration with libraries such as Vitest, Jest, Playwright, Cypress, and Storybook. - Generators for applica

227 lines (226 loc) • 10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.remixApplicationGenerator = remixApplicationGenerator; exports.remixApplicationGeneratorInternal = remixApplicationGeneratorInternal; const devkit_1 = require("@nx/devkit"); const log_show_project_command_1 = require("@nx/devkit/src/utils/log-show-project-command"); const js_1 = require("@nx/js"); const create_ts_config_1 = require("@nx/js/src/utils/typescript/create-ts-config"); const onboarding_1 = require("nx/src/nx-cloud/utilities/onboarding"); const testing_config_utils_1 = require("../../utils/testing-config-utils"); const versions_1 = require("../../utils/versions"); const init_1 = require("../init/init"); const update_dependencies_1 = require("../utils/update-dependencies"); const lib_1 = require("./lib"); const ts_solution_setup_1 = require("@nx/js/src/utils/typescript/ts-solution-setup"); const sort_fields_1 = require("@nx/js/src/utils/package-json/sort-fields"); function remixApplicationGenerator(tree, options) { return remixApplicationGeneratorInternal(tree, { addPlugin: true, useProjectJson: true, ...options, }); } async function remixApplicationGeneratorInternal(tree, _options) { const tasks = [ await (0, init_1.default)(tree, { skipFormat: true, addPlugin: true, }), await (0, js_1.initGenerator)(tree, { skipFormat: true, addTsPlugin: _options.useTsSolution, formatter: _options.formatter, platform: 'web', }), ]; const options = await (0, lib_1.normalizeOptions)(tree, _options); if (!options.addPlugin) { throw new Error(`To generate a new Remix Vite application, you must use Inference Plugins. Check you do not have NX_ADD_PLUGINS=false or useInferencePlugins: false in your nx.json.`); } // If we are using the new TS solution // We need to update the workspace file (package.json or pnpm-workspaces.yaml) to include the new project if (options.isUsingTsSolutionConfig) { await (0, ts_solution_setup_1.addProjectToTsSolutionWorkspace)(tree, options.projectRoot); } if (options.useProjectJson) { (0, devkit_1.addProjectConfiguration)(tree, options.projectName, { root: options.projectRoot, sourceRoot: `${options.projectRoot}`, projectType: 'application', tags: options.parsedTags, targets: {}, }); } const installTask = (0, update_dependencies_1.updateDependencies)(tree); tasks.push(installTask); const onBoardingStatus = await (0, onboarding_1.createNxCloudOnboardingURLForWelcomeApp)(tree, options.nxCloudToken); const connectCloudUrl = onBoardingStatus === 'unclaimed' && (await (0, onboarding_1.getNxCloudAppOnBoardingUrl)(options.nxCloudToken)); const vars = { ...options, tmpl: '', offsetFromRoot: (0, devkit_1.offsetFromRoot)(options.projectRoot), remixVersion: versions_1.remixVersion, isbotVersion: versions_1.isbotVersion, reactVersion: versions_1.reactVersion, reactDomVersion: versions_1.reactDomVersion, typesReactVersion: versions_1.typesReactVersion, typesReactDomVersion: versions_1.typesReactDomVersion, eslintVersion: versions_1.eslintVersion, typescriptVersion: versions_1.typescriptVersion, viteVersion: versions_1.viteVersion, }; (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files/common'), options.projectRoot, vars); (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, './files/nx-welcome', onBoardingStatus), options.projectRoot, { ...vars, connectCloudUrl }); if (options.rootProject) { const gitignore = tree.read('.gitignore', 'utf-8'); tree.write('.gitignore', `${gitignore}\n.cache\nbuild\npublic/build\n.env\n`); } else { (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files/non-root'), options.projectRoot, vars); } if (options.isUsingTsSolutionConfig) { (0, devkit_1.generateFiles)(tree, (0, devkit_1.joinPathFragments)(__dirname, 'files/ts-solution'), options.projectRoot, vars); } if (!options.useProjectJson) { (0, devkit_1.updateJson)(tree, (0, devkit_1.joinPathFragments)(options.projectRoot, 'package.json'), (json) => { if (options.projectName !== options.importPath) { json.nx = { name: options.projectName }; } if (options.parsedTags?.length) { json.nx ??= {}; json.nx.tags = options.parsedTags; } return json; }); } if (options.unitTestRunner !== 'none') { if (options.unitTestRunner === 'vitest') { const { vitestGenerator, createOrEditViteConfig } = (0, devkit_1.ensurePackage)('@nx/vite', (0, versions_1.getPackageVersion)(tree, 'nx')); const vitestTask = await vitestGenerator(tree, { uiFramework: 'react', project: options.projectName, coverageProvider: 'v8', inSourceTests: false, skipFormat: true, testEnvironment: 'jsdom', skipViteConfig: true, addPlugin: true, }); createOrEditViteConfig(tree, { project: options.projectName, includeLib: false, includeVitest: true, testEnvironment: 'jsdom', imports: [`import react from '@vitejs/plugin-react';`], plugins: [`react()`], }, true, undefined, true); tasks.push(vitestTask); } else { const { configurationGenerator: jestConfigurationGenerator } = (0, devkit_1.ensurePackage)('@nx/jest', (0, versions_1.getPackageVersion)(tree, 'nx')); const jestTask = await jestConfigurationGenerator(tree, { project: options.projectName, setupFile: 'none', supportTsx: true, skipSerializers: false, skipPackageJson: false, skipFormat: true, addPlugin: true, compiler: options.useTsSolution ? 'swc' : undefined, }); const projectConfig = (0, devkit_1.readProjectConfiguration)(tree, options.projectName); if (projectConfig.targets?.['test']?.options) { projectConfig.targets['test'].options.passWithNoTests = true; (0, devkit_1.updateProjectConfiguration)(tree, options.projectName, projectConfig); } tasks.push(jestTask); } const pkgInstallTask = (0, lib_1.updateUnitTestConfig)(tree, options.projectRoot, options.unitTestRunner, options.rootProject); tasks.push(pkgInstallTask); } else { tree.delete((0, devkit_1.joinPathFragments)(options.projectRoot, `tests/routes/_index.spec.tsx`)); } if (options.linter !== 'none') { const { lintProjectGenerator } = (0, devkit_1.ensurePackage)('@nx/eslint', (0, versions_1.getPackageVersion)(tree, 'nx')); const { addIgnoresToLintConfig } = await Promise.resolve().then(() => require('@nx/eslint/src/generators/utils/eslint-file')); const eslintTask = await lintProjectGenerator(tree, { linter: options.linter, project: options.projectName, tsConfigPaths: [ (0, devkit_1.joinPathFragments)(options.projectRoot, 'tsconfig.app.json'), ], unitTestRunner: options.unitTestRunner, skipFormat: true, rootProject: options.rootProject, addPlugin: options.addPlugin, }); tasks.push(eslintTask); addIgnoresToLintConfig(tree, options.projectRoot, [ 'build', 'public/build', ]); } if (options.rootProject && tree.exists('tsconfig.base.json')) { // If this is a standalone project, merge tsconfig.json and tsconfig.base.json. const tsConfigBaseJson = (0, devkit_1.readJson)(tree, 'tsconfig.base.json'); (0, devkit_1.updateJson)(tree, 'tsconfig.json', (json) => { delete json.extends; json.compilerOptions = { ...tsConfigBaseJson.compilerOptions, ...json.compilerOptions, // Taken from remix default setup // https://github.com/remix-run/remix/blob/68c8982/templates/remix/tsconfig.json#L15-L17 paths: { '~/*': ['./app/*'], }, }; json.include = [ ...(tsConfigBaseJson.include ?? []), ...(json.include ?? []), ]; json.exclude = [ ...(tsConfigBaseJson.exclude ?? []), ...(json.exclude ?? []), ]; return json; }); tree.delete('tsconfig.base.json'); } else { // Otherwise, extract the tsconfig.base.json from tsconfig.json so we can share settings. (0, create_ts_config_1.extractTsConfigBase)(tree); } if (options.rootProject) { (0, devkit_1.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.js'; export default {...nxPreset}; `); (0, testing_config_utils_1.updateJestTestMatch)(tree, 'jest.config.ts', '<rootDir>/tests/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'); } } tasks.push(await (0, lib_1.addE2E)(tree, options)); await (0, lib_1.ignoreViteTempFiles)(tree, options.projectRoot); (0, ts_solution_setup_1.updateTsconfigFiles)(tree, options.projectRoot, 'tsconfig.app.json', { jsx: 'react-jsx', module: 'esnext', moduleResolution: 'bundler', }, options.linter === 'eslint' ? ['eslint.config.js', 'eslint.config.cjs', 'eslint.config.mjs'] : undefined, '.'); (0, sort_fields_1.sortPackageJsonFields)(tree, options.projectRoot); if (!options.skipFormat) { await (0, devkit_1.formatFiles)(tree); } tasks.push(() => { (0, log_show_project_command_1.logShowProjectCommand)(options.projectName); }); return (0, devkit_1.runTasksInSerial)(...tasks); } exports.default = remixApplicationGenerator;