feat(remix): infer targets for remix vite in @nx/remix/plugin (#27713)
- feat(remix): add createnodesv2 - feat(remix): support vite in the plugin - feat(remix): support remix vite in plugin - fix(remix): init should ues addPlugin v2 <!-- Please make sure you have read the submission guidelines before posting an PR --> <!-- https://github.com/nrwl/nx/blob/master/CONTRIBUTING.md#-submitting-a-pr --> <!-- Please make sure that your commit message follows our format --> <!-- Example: `fix(nx): must begin with lowercase` --> <!-- If this is a particularly complex change or feature addition, you can request a dedicated Nx release for this pull request branch. Mention someone from the Nx team or the `@nrwl/nx-pipelines-reviewers` and they will confirm if the PR warrants its own release for testing purposes, and generate it for you if appropriate. --> ## Current Behavior <!-- This is the behavior we have today --> Nx does not currently infer targets when someone is using remix w/ vite ## Expected Behavior <!-- This is the behavior we should expect with the changes in this PR --> Nx should infer targets for remix vite apps ## Related Issue(s) <!-- Please link the issue being fixed so it gets closed when this is merged. --> Fixes #
This commit is contained in:
parent
27a01861c3
commit
ef7b66800a
@ -1,5 +1,6 @@
|
|||||||
export {
|
export {
|
||||||
createNodes,
|
createNodes,
|
||||||
|
createNodesV2,
|
||||||
createDependencies,
|
createDependencies,
|
||||||
RemixPluginOptions,
|
RemixPluginOptions,
|
||||||
} from './src/plugins/plugin';
|
} from './src/plugins/plugin';
|
||||||
|
|||||||
@ -39,6 +39,7 @@ describe('Remix Init Generator', () => {
|
|||||||
"options": {
|
"options": {
|
||||||
"buildTargetName": "build",
|
"buildTargetName": "build",
|
||||||
"devTargetName": "dev",
|
"devTargetName": "dev",
|
||||||
|
"serveStaticTargetName": "serve-static",
|
||||||
"startTargetName": "start",
|
"startTargetName": "start",
|
||||||
"typecheckTargetName": "typecheck",
|
"typecheckTargetName": "typecheck",
|
||||||
},
|
},
|
||||||
|
|||||||
@ -8,10 +8,10 @@ import {
|
|||||||
createProjectGraphAsync,
|
createProjectGraphAsync,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import {
|
import {
|
||||||
addPluginV1,
|
addPlugin,
|
||||||
generateCombinations,
|
generateCombinations,
|
||||||
} from '@nx/devkit/src/utils/add-plugin';
|
} from '@nx/devkit/src/utils/add-plugin';
|
||||||
import { createNodes } from '../../plugins/plugin';
|
import { createNodesV2 } from '../../plugins/plugin';
|
||||||
import { nxVersion, remixVersion } from '../../utils/versions';
|
import { nxVersion, remixVersion } from '../../utils/versions';
|
||||||
import { type Schema } from './schema';
|
import { type Schema } from './schema';
|
||||||
|
|
||||||
@ -44,11 +44,11 @@ export async function remixInitGeneratorInternal(tree: Tree, options: Schema) {
|
|||||||
nxJson.useInferencePlugins !== false;
|
nxJson.useInferencePlugins !== false;
|
||||||
options.addPlugin ??= addPluginDefault;
|
options.addPlugin ??= addPluginDefault;
|
||||||
if (options.addPlugin) {
|
if (options.addPlugin) {
|
||||||
await addPluginV1(
|
await addPlugin(
|
||||||
tree,
|
tree,
|
||||||
await createProjectGraphAsync(),
|
await createProjectGraphAsync(),
|
||||||
'@nx/remix/plugin',
|
'@nx/remix/plugin',
|
||||||
createNodes,
|
createNodesV2,
|
||||||
{
|
{
|
||||||
startTargetName: ['start', 'remix:start', 'remix-start'],
|
startTargetName: ['start', 'remix:start', 'remix-start'],
|
||||||
buildTargetName: ['build', 'remix:build', 'remix-build'],
|
buildTargetName: ['build', 'remix:build', 'remix-build'],
|
||||||
@ -58,6 +58,11 @@ export async function remixInitGeneratorInternal(tree: Tree, options: Schema) {
|
|||||||
'remix:typecheck',
|
'remix:typecheck',
|
||||||
'remix-typecheck',
|
'remix-typecheck',
|
||||||
],
|
],
|
||||||
|
serveStaticTargetName: [
|
||||||
|
'serve-static',
|
||||||
|
'vite:serve-static',
|
||||||
|
'vite-serve-static',
|
||||||
|
],
|
||||||
},
|
},
|
||||||
options.updatePackageScripts
|
options.updatePackageScripts
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,169 +1,359 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`@nx/remix/plugin non-root project should create nodes 1`] = `
|
exports[`@nx/remix/plugin Remix Classic Compiler non-root project should create nodes 1`] = `
|
||||||
{
|
[
|
||||||
"projects": {
|
[
|
||||||
"my-app": {
|
"my-app/remix.config.cjs",
|
||||||
"root": "my-app",
|
{
|
||||||
"targets": {
|
"projects": {
|
||||||
"build": {
|
"my-app": {
|
||||||
"cache": true,
|
"metadata": {},
|
||||||
"command": "remix build",
|
"root": "my-app",
|
||||||
"dependsOn": [
|
"targets": {
|
||||||
"^build",
|
"build": {
|
||||||
],
|
"cache": true,
|
||||||
"inputs": [
|
"command": "remix build",
|
||||||
"production",
|
"dependsOn": [
|
||||||
"^production",
|
"^build",
|
||||||
{
|
],
|
||||||
"externalDependencies": [
|
"inputs": [
|
||||||
"@remix-run/dev",
|
"production",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"@remix-run/dev",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "my-app",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{workspaceRoot}/my-app/build",
|
||||||
|
"{workspaceRoot}/my-app/public/build",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
"dev": {
|
||||||
"options": {
|
"command": "remix dev --manual",
|
||||||
"cwd": "my-app",
|
"options": {
|
||||||
},
|
"cwd": "my-app",
|
||||||
"outputs": [
|
},
|
||||||
"{workspaceRoot}/my-app/build",
|
},
|
||||||
"{workspaceRoot}/my-app/public/build",
|
"serve-static": {
|
||||||
],
|
"command": "remix-serve build/index.js",
|
||||||
},
|
"dependsOn": [
|
||||||
"dev": {
|
"build",
|
||||||
"command": "remix dev --manual",
|
],
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "my-app",
|
"cwd": "my-app",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"serve-static": {
|
"start": {
|
||||||
"command": "remix-serve build/index.js",
|
"command": "remix-serve build/index.js",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"build",
|
"build",
|
||||||
],
|
],
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "my-app",
|
"cwd": "my-app",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"start": {
|
"static-serve": {
|
||||||
"command": "remix-serve build/index.js",
|
"command": "remix-serve build/index.js",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"build",
|
"build",
|
||||||
],
|
],
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "my-app",
|
"cwd": "my-app",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"static-serve": {
|
"tsc": {
|
||||||
"command": "remix-serve build/index.js",
|
"cache": true,
|
||||||
"dependsOn": [
|
"command": "tsc",
|
||||||
"build",
|
"inputs": [
|
||||||
],
|
"production",
|
||||||
"options": {
|
"^production",
|
||||||
"cwd": "my-app",
|
{
|
||||||
},
|
"externalDependencies": [
|
||||||
},
|
"typescript",
|
||||||
"tsc": {
|
],
|
||||||
"cache": true,
|
},
|
||||||
"command": "tsc",
|
],
|
||||||
"inputs": [
|
"options": {
|
||||||
"production",
|
"cwd": "my-app",
|
||||||
"^production",
|
},
|
||||||
{
|
|
||||||
"externalDependencies": [
|
|
||||||
"typescript",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"cwd": "my-app",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
}
|
]
|
||||||
`;
|
`;
|
||||||
|
|
||||||
exports[`@nx/remix/plugin root project should create nodes 1`] = `
|
exports[`@nx/remix/plugin Remix Classic Compiler root project should create nodes 1`] = `
|
||||||
{
|
[
|
||||||
"projects": {
|
[
|
||||||
".": {
|
"remix.config.cjs",
|
||||||
"root": ".",
|
{
|
||||||
"targets": {
|
"projects": {
|
||||||
"build": {
|
".": {
|
||||||
"cache": true,
|
"metadata": {},
|
||||||
"command": "remix build",
|
"root": ".",
|
||||||
"dependsOn": [
|
"targets": {
|
||||||
"^build",
|
"build": {
|
||||||
],
|
"cache": true,
|
||||||
"inputs": [
|
"command": "remix build",
|
||||||
"production",
|
"dependsOn": [
|
||||||
"^production",
|
"^build",
|
||||||
{
|
],
|
||||||
"externalDependencies": [
|
"inputs": [
|
||||||
"@remix-run/dev",
|
"production",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"@remix-run/dev",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{workspaceRoot}/build",
|
||||||
|
"{workspaceRoot}/public/build",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
],
|
"dev": {
|
||||||
"options": {
|
"command": "remix dev --manual",
|
||||||
"cwd": ".",
|
"options": {
|
||||||
},
|
"cwd": ".",
|
||||||
"outputs": [
|
},
|
||||||
"{workspaceRoot}/build",
|
},
|
||||||
"{workspaceRoot}/public/build",
|
"serve-static": {
|
||||||
],
|
"command": "remix-serve build/index.js",
|
||||||
},
|
"dependsOn": [
|
||||||
"dev": {
|
"build",
|
||||||
"command": "remix dev --manual",
|
],
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": ".",
|
"cwd": ".",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"serve-static": {
|
"start": {
|
||||||
"command": "remix-serve build/index.js",
|
"command": "remix-serve build/index.js",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"build",
|
"build",
|
||||||
],
|
],
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": ".",
|
"cwd": ".",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"start": {
|
"static-serve": {
|
||||||
"command": "remix-serve build/index.js",
|
"command": "remix-serve build/index.js",
|
||||||
"dependsOn": [
|
"dependsOn": [
|
||||||
"build",
|
"build",
|
||||||
],
|
],
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": ".",
|
"cwd": ".",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
"static-serve": {
|
"typecheck": {
|
||||||
"command": "remix-serve build/index.js",
|
"cache": true,
|
||||||
"dependsOn": [
|
"command": "tsc",
|
||||||
"build",
|
"inputs": [
|
||||||
],
|
"production",
|
||||||
"options": {
|
"^production",
|
||||||
"cwd": ".",
|
{
|
||||||
},
|
"externalDependencies": [
|
||||||
},
|
"typescript",
|
||||||
"typecheck": {
|
],
|
||||||
"cache": true,
|
},
|
||||||
"command": "tsc",
|
],
|
||||||
"inputs": [
|
"options": {
|
||||||
"production",
|
"cwd": ".",
|
||||||
"^production",
|
},
|
||||||
{
|
|
||||||
"externalDependencies": [
|
|
||||||
"typescript",
|
|
||||||
],
|
|
||||||
},
|
},
|
||||||
],
|
|
||||||
"options": {
|
|
||||||
"cwd": ".",
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
],
|
||||||
}
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`@nx/remix/plugin Remix Vite Compiler non-root project should create nodes 1`] = `
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"my-app/vite.config.js",
|
||||||
|
{
|
||||||
|
"projects": {
|
||||||
|
"my-app": {
|
||||||
|
"metadata": {},
|
||||||
|
"root": "my-app",
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"cache": true,
|
||||||
|
"command": "remix vite:build",
|
||||||
|
"dependsOn": [
|
||||||
|
"^build",
|
||||||
|
],
|
||||||
|
"inputs": [
|
||||||
|
"production",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"@remix-run/dev",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "my-app",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{workspaceRoot}/my-app/build",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"dev": {
|
||||||
|
"command": "remix vite:dev",
|
||||||
|
"options": {
|
||||||
|
"cwd": "my-app",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"serve-static": {
|
||||||
|
"command": "remix-serve build/server/index.js",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "my-app",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
"command": "remix-serve build/server/index.js",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "my-app",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"static-serve": {
|
||||||
|
"command": "remix-serve build/server/index.js",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "my-app",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"tsc": {
|
||||||
|
"cache": true,
|
||||||
|
"command": "tsc",
|
||||||
|
"inputs": [
|
||||||
|
"production",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"typescript",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": "my-app",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
|
`;
|
||||||
|
|
||||||
|
exports[`@nx/remix/plugin Remix Vite Compiler root project should create nodes 1`] = `
|
||||||
|
[
|
||||||
|
[
|
||||||
|
"vite.config.js",
|
||||||
|
{
|
||||||
|
"projects": {
|
||||||
|
".": {
|
||||||
|
"metadata": {},
|
||||||
|
"root": ".",
|
||||||
|
"targets": {
|
||||||
|
"build": {
|
||||||
|
"cache": true,
|
||||||
|
"command": "remix vite:build",
|
||||||
|
"dependsOn": [
|
||||||
|
"^build",
|
||||||
|
],
|
||||||
|
"inputs": [
|
||||||
|
"production",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"@remix-run/dev",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
"outputs": [
|
||||||
|
"{workspaceRoot}/build",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"dev": {
|
||||||
|
"command": "remix vite:dev",
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"serve-static": {
|
||||||
|
"command": "remix-serve build/server/index.js",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"start": {
|
||||||
|
"command": "remix-serve build/server/index.js",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"static-serve": {
|
||||||
|
"command": "remix-serve build/server/index.js",
|
||||||
|
"dependsOn": [
|
||||||
|
"build",
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
"typecheck": {
|
||||||
|
"cache": true,
|
||||||
|
"command": "tsc",
|
||||||
|
"inputs": [
|
||||||
|
"production",
|
||||||
|
"^production",
|
||||||
|
{
|
||||||
|
"externalDependencies": [
|
||||||
|
"typescript",
|
||||||
|
],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
"options": {
|
||||||
|
"cwd": ".",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
],
|
||||||
|
]
|
||||||
`;
|
`;
|
||||||
|
|||||||
@ -1,48 +1,56 @@
|
|||||||
import { type CreateNodesContext, joinPathFragments } from '@nx/devkit';
|
import { type CreateNodesContext, joinPathFragments } from '@nx/devkit';
|
||||||
import { createNodes } from './plugin';
|
import { createNodesV2 as createNodes } from './plugin';
|
||||||
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
|
import { TempFs } from 'nx/src/internal-testing-utils/temp-fs';
|
||||||
|
import { loadViteDynamicImport } from '../utils/executor-utils';
|
||||||
|
|
||||||
|
jest.mock('../utils/executor-utils', () => ({
|
||||||
|
loadViteDynamicImport: jest.fn().mockResolvedValue({
|
||||||
|
resolveConfig: jest.fn().mockResolvedValue({}),
|
||||||
|
}),
|
||||||
|
}));
|
||||||
|
|
||||||
describe('@nx/remix/plugin', () => {
|
describe('@nx/remix/plugin', () => {
|
||||||
let createNodesFunction = createNodes[1];
|
let createNodesFunction = createNodes[1];
|
||||||
let context: CreateNodesContext;
|
let context: CreateNodesContext;
|
||||||
let cwd = process.cwd();
|
let cwd = process.cwd();
|
||||||
|
|
||||||
describe('root project', () => {
|
describe('Remix Classic Compiler', () => {
|
||||||
const tempFs = new TempFs('test');
|
describe('root project', () => {
|
||||||
|
const tempFs = new TempFs('test');
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
context = {
|
context = {
|
||||||
nxJsonConfiguration: {
|
nxJsonConfiguration: {
|
||||||
targetDefaults: {
|
targetDefaults: {
|
||||||
build: {
|
build: {
|
||||||
cache: false,
|
cache: false,
|
||||||
inputs: ['foo', '^foo'],
|
inputs: ['foo', '^foo'],
|
||||||
|
},
|
||||||
|
dev: {
|
||||||
|
command: 'npm run dev',
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
command: 'npm run start',
|
||||||
|
},
|
||||||
|
typecheck: {
|
||||||
|
command: 'tsc',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
dev: {
|
namedInputs: {
|
||||||
command: 'npm run dev',
|
default: ['{projectRoot}/**/*'],
|
||||||
},
|
production: ['!{projectRoot}/**/*.spec.ts'],
|
||||||
start: {
|
|
||||||
command: 'npm run start',
|
|
||||||
},
|
|
||||||
typecheck: {
|
|
||||||
command: 'tsc',
|
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
namedInputs: {
|
workspaceRoot: tempFs.tempDir,
|
||||||
default: ['{projectRoot}/**/*'],
|
configFiles: [],
|
||||||
production: ['!{projectRoot}/**/*.spec.ts'],
|
};
|
||||||
},
|
tempFs.createFileSync(
|
||||||
},
|
'package.json',
|
||||||
workspaceRoot: tempFs.tempDir,
|
JSON.stringify('{name: "my-app", type: "module"}')
|
||||||
configFiles: [],
|
);
|
||||||
};
|
tempFs.createFileSync(
|
||||||
tempFs.createFileSync(
|
'remix.config.cjs',
|
||||||
'package.json',
|
`/**
|
||||||
JSON.stringify('{name: "my-app", type: "module"}')
|
|
||||||
);
|
|
||||||
tempFs.createFileSync(
|
|
||||||
'remix.config.cjs',
|
|
||||||
`/**
|
|
||||||
* @type {import('@remix-run/dev').AppConfig}
|
* @type {import('@remix-run/dev').AppConfig}
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
module.exports = {
|
||||||
@ -50,92 +58,241 @@ module.exports = {
|
|||||||
watchPaths: () => require('@nx/remix').createWatchPaths(__dirname),
|
watchPaths: () => require('@nx/remix').createWatchPaths(__dirname),
|
||||||
};
|
};
|
||||||
`
|
`
|
||||||
);
|
);
|
||||||
process.chdir(tempFs.tempDir);
|
process.chdir(tempFs.tempDir);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
tempFs.cleanup();
|
||||||
|
process.chdir(cwd);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create nodes', async () => {
|
||||||
|
// ACT
|
||||||
|
const nodes = await createNodesFunction(
|
||||||
|
['remix.config.cjs'],
|
||||||
|
{
|
||||||
|
buildTargetName: 'build',
|
||||||
|
devTargetName: 'dev',
|
||||||
|
startTargetName: 'start',
|
||||||
|
typecheckTargetName: 'typecheck',
|
||||||
|
staticServeTargetName: 'static-serve',
|
||||||
|
},
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
// ASSERT
|
||||||
|
expect(nodes).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
describe('non-root project', () => {
|
||||||
jest.resetModules();
|
const tempFs = new TempFs('test');
|
||||||
tempFs.cleanup();
|
|
||||||
process.chdir(cwd);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create nodes', async () => {
|
beforeEach(() => {
|
||||||
// ACT
|
context = {
|
||||||
const nodes = await createNodesFunction(
|
nxJsonConfiguration: {
|
||||||
'remix.config.cjs',
|
namedInputs: {
|
||||||
{
|
default: ['{projectRoot}/**/*'],
|
||||||
buildTargetName: 'build',
|
production: ['!{projectRoot}/**/*.spec.ts'],
|
||||||
devTargetName: 'dev',
|
},
|
||||||
startTargetName: 'start',
|
},
|
||||||
typecheckTargetName: 'typecheck',
|
workspaceRoot: tempFs.tempDir,
|
||||||
staticServeTargetName: 'static-serve',
|
configFiles: [],
|
||||||
},
|
};
|
||||||
context
|
|
||||||
);
|
|
||||||
|
|
||||||
// ASSERT
|
tempFs.createFileSync(
|
||||||
expect(nodes).toMatchSnapshot();
|
'my-app/project.json',
|
||||||
|
JSON.stringify({ name: 'my-app' })
|
||||||
|
);
|
||||||
|
|
||||||
|
tempFs.createFileSync(
|
||||||
|
'my-app/remix.config.cjs',
|
||||||
|
`/**
|
||||||
|
* @type {import('@remix-run/dev').AppConfig}
|
||||||
|
*/
|
||||||
|
module.exports = {
|
||||||
|
ignoredRouteFiles: ['**/.*'],
|
||||||
|
watchPaths: () => require('@nx/remix').createWatchPaths(__dirname),
|
||||||
|
};
|
||||||
|
`
|
||||||
|
);
|
||||||
|
|
||||||
|
process.chdir(tempFs.tempDir);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
tempFs.cleanup();
|
||||||
|
process.chdir(cwd);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create nodes', async () => {
|
||||||
|
// ACT
|
||||||
|
const nodes = await createNodesFunction(
|
||||||
|
['my-app/remix.config.cjs'],
|
||||||
|
{
|
||||||
|
buildTargetName: 'build',
|
||||||
|
devTargetName: 'dev',
|
||||||
|
startTargetName: 'start',
|
||||||
|
typecheckTargetName: 'tsc',
|
||||||
|
staticServeTargetName: 'static-serve',
|
||||||
|
},
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
// ASSERT
|
||||||
|
expect(nodes).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('non-root project', () => {
|
describe('Remix Vite Compiler', () => {
|
||||||
const tempFs = new TempFs('test');
|
describe('root project', () => {
|
||||||
|
const tempFs = new TempFs('test');
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
context = {
|
context = {
|
||||||
nxJsonConfiguration: {
|
nxJsonConfiguration: {
|
||||||
namedInputs: {
|
targetDefaults: {
|
||||||
default: ['{projectRoot}/**/*'],
|
build: {
|
||||||
production: ['!{projectRoot}/**/*.spec.ts'],
|
cache: false,
|
||||||
|
inputs: ['foo', '^foo'],
|
||||||
|
},
|
||||||
|
dev: {
|
||||||
|
command: 'npm run dev',
|
||||||
|
},
|
||||||
|
start: {
|
||||||
|
command: 'npm run start',
|
||||||
|
},
|
||||||
|
typecheck: {
|
||||||
|
command: 'tsc',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
namedInputs: {
|
||||||
|
default: ['{projectRoot}/**/*'],
|
||||||
|
production: ['!{projectRoot}/**/*.spec.ts'],
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
workspaceRoot: tempFs.tempDir,
|
||||||
workspaceRoot: tempFs.tempDir,
|
configFiles: [],
|
||||||
configFiles: [],
|
};
|
||||||
};
|
tempFs.createFileSync(
|
||||||
|
'package.json',
|
||||||
|
JSON.stringify('{name: "my-app", type: "module"}')
|
||||||
|
);
|
||||||
|
tempFs.createFileSync(
|
||||||
|
'vite.config.js',
|
||||||
|
`const {defineConfig} = require('vite');
|
||||||
|
const { vitePlugin: remix } = require('@remix-run/dev');
|
||||||
|
module.exports = defineConfig({
|
||||||
|
plugins:[remix()]
|
||||||
|
});`
|
||||||
|
);
|
||||||
|
process.chdir(tempFs.tempDir);
|
||||||
|
(loadViteDynamicImport as jest.Mock).mockResolvedValue({
|
||||||
|
resolveConfig: jest.fn().mockResolvedValue({
|
||||||
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: 'index.ts',
|
||||||
|
name: 'my-app',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
tempFs.createFileSync(
|
afterEach(() => {
|
||||||
'my-app/project.json',
|
jest.resetModules();
|
||||||
JSON.stringify({ name: 'my-app' })
|
tempFs.cleanup();
|
||||||
);
|
process.chdir(cwd);
|
||||||
|
});
|
||||||
|
|
||||||
tempFs.createFileSync(
|
it('should create nodes', async () => {
|
||||||
'my-app/remix.config.cjs',
|
// ACT
|
||||||
`/**
|
const nodes = await createNodesFunction(
|
||||||
* @type {import('@remix-run/dev').AppConfig}
|
['vite.config.js'],
|
||||||
*/
|
{
|
||||||
module.exports = {
|
buildTargetName: 'build',
|
||||||
ignoredRouteFiles: ['**/.*'],
|
devTargetName: 'dev',
|
||||||
watchPaths: () => require('@nx/remix').createWatchPaths(__dirname),
|
startTargetName: 'start',
|
||||||
};
|
typecheckTargetName: 'typecheck',
|
||||||
`
|
staticServeTargetName: 'static-serve',
|
||||||
);
|
},
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
process.chdir(tempFs.tempDir);
|
// ASSERT
|
||||||
|
expect(nodes).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
afterEach(() => {
|
describe('non-root project', () => {
|
||||||
jest.resetModules();
|
const tempFs = new TempFs('test');
|
||||||
tempFs.cleanup();
|
|
||||||
process.chdir(cwd);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should create nodes', async () => {
|
beforeEach(() => {
|
||||||
// ACT
|
context = {
|
||||||
const nodes = await createNodesFunction(
|
nxJsonConfiguration: {
|
||||||
'my-app/remix.config.cjs',
|
namedInputs: {
|
||||||
{
|
default: ['{projectRoot}/**/*'],
|
||||||
buildTargetName: 'build',
|
production: ['!{projectRoot}/**/*.spec.ts'],
|
||||||
devTargetName: 'dev',
|
},
|
||||||
startTargetName: 'start',
|
},
|
||||||
typecheckTargetName: 'tsc',
|
workspaceRoot: tempFs.tempDir,
|
||||||
staticServeTargetName: 'static-serve',
|
configFiles: [],
|
||||||
},
|
};
|
||||||
context
|
|
||||||
);
|
|
||||||
|
|
||||||
// ASSERT
|
tempFs.createFileSync(
|
||||||
expect(nodes).toMatchSnapshot();
|
'my-app/project.json',
|
||||||
|
JSON.stringify({ name: 'my-app' })
|
||||||
|
);
|
||||||
|
|
||||||
|
tempFs.createFileSync(
|
||||||
|
'my-app/vite.config.js',
|
||||||
|
`const {defineConfig} = require('vite');
|
||||||
|
const { vitePlugin: remix } = require('@remix-run/dev');
|
||||||
|
module.exports = defineConfig({
|
||||||
|
plugins:[remix()]
|
||||||
|
});`
|
||||||
|
);
|
||||||
|
(loadViteDynamicImport as jest.Mock).mockResolvedValue({
|
||||||
|
resolveConfig: jest.fn().mockResolvedValue({
|
||||||
|
build: {
|
||||||
|
lib: {
|
||||||
|
entry: 'index.ts',
|
||||||
|
name: 'my-app',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
process.chdir(tempFs.tempDir);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.resetModules();
|
||||||
|
tempFs.cleanup();
|
||||||
|
process.chdir(cwd);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should create nodes', async () => {
|
||||||
|
// ACT
|
||||||
|
const nodes = await createNodesFunction(
|
||||||
|
['my-app/vite.config.js'],
|
||||||
|
{
|
||||||
|
buildTargetName: 'build',
|
||||||
|
devTargetName: 'dev',
|
||||||
|
startTargetName: 'start',
|
||||||
|
typecheckTargetName: 'tsc',
|
||||||
|
staticServeTargetName: 'static-serve',
|
||||||
|
},
|
||||||
|
context
|
||||||
|
);
|
||||||
|
|
||||||
|
// ASSERT
|
||||||
|
expect(nodes).toMatchSnapshot();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -1,44 +1,27 @@
|
|||||||
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
import { workspaceDataDirectory } from 'nx/src/utils/cache-directory';
|
||||||
|
import { hashObject } from 'nx/src/hasher/file-hasher';
|
||||||
import {
|
import {
|
||||||
type CreateDependencies,
|
type CreateDependencies,
|
||||||
type CreateNodes,
|
type CreateNodes,
|
||||||
type CreateNodesContext,
|
type CreateNodesContext,
|
||||||
|
createNodesFromFiles,
|
||||||
|
CreateNodesV2,
|
||||||
detectPackageManager,
|
detectPackageManager,
|
||||||
joinPathFragments,
|
joinPathFragments,
|
||||||
|
logger,
|
||||||
|
ProjectConfiguration,
|
||||||
readJsonFile,
|
readJsonFile,
|
||||||
type TargetConfiguration,
|
type TargetConfiguration,
|
||||||
writeJsonFile,
|
writeJsonFile,
|
||||||
} from '@nx/devkit';
|
} from '@nx/devkit';
|
||||||
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
|
import { calculateHashForCreateNodes } from '@nx/devkit/src/utils/calculate-hash-for-create-nodes';
|
||||||
import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
|
import { getNamedInputs } from '@nx/devkit/src/utils/get-named-inputs';
|
||||||
|
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
|
||||||
import { getLockFileName } from '@nx/js';
|
import { getLockFileName } from '@nx/js';
|
||||||
import { type AppConfig } from '@remix-run/dev';
|
import { type AppConfig } from '@remix-run/dev';
|
||||||
import { dirname, join } from 'path';
|
import { dirname, isAbsolute, join, relative } from 'path';
|
||||||
import { existsSync, readdirSync } from 'fs';
|
import { existsSync, readdirSync, readFileSync } from 'fs';
|
||||||
import { loadConfigFile } from '@nx/devkit/src/utils/config-utils';
|
import { loadViteDynamicImport } from '../utils/executor-utils';
|
||||||
|
|
||||||
const cachePath = join(workspaceDataDirectory, 'remix.hash');
|
|
||||||
const targetsCache = readTargetsCache();
|
|
||||||
|
|
||||||
function readTargetsCache(): Record<
|
|
||||||
string,
|
|
||||||
Record<string, TargetConfiguration>
|
|
||||||
> {
|
|
||||||
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
|
|
||||||
}
|
|
||||||
|
|
||||||
function writeTargetsToCache() {
|
|
||||||
const oldCache = readTargetsCache();
|
|
||||||
writeJsonFile(cachePath, {
|
|
||||||
...oldCache,
|
|
||||||
...targetsCache,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export const createDependencies: CreateDependencies = () => {
|
|
||||||
writeTargetsToCache();
|
|
||||||
return [];
|
|
||||||
};
|
|
||||||
|
|
||||||
export interface RemixPluginOptions {
|
export interface RemixPluginOptions {
|
||||||
buildTargetName?: string;
|
buildTargetName?: string;
|
||||||
@ -51,60 +34,133 @@ export interface RemixPluginOptions {
|
|||||||
staticServeTargetName?: string;
|
staticServeTargetName?: string;
|
||||||
serveStaticTargetName?: string;
|
serveStaticTargetName?: string;
|
||||||
}
|
}
|
||||||
|
type RemixTargets = Pick<ProjectConfiguration, 'targets' | 'metadata'>;
|
||||||
|
|
||||||
export const createNodes: CreateNodes<RemixPluginOptions> = [
|
function readTargetsCache(
|
||||||
'**/remix.config.{js,cjs,mjs}',
|
cachePath: string
|
||||||
async (configFilePath, options, context) => {
|
): Record<string, Record<string, TargetConfiguration>> {
|
||||||
const projectRoot = dirname(configFilePath);
|
return existsSync(cachePath) ? readJsonFile(cachePath) : {};
|
||||||
const fullyQualifiedProjectRoot = join(context.workspaceRoot, projectRoot);
|
}
|
||||||
// Do not create a project if package.json and project.json isn't there
|
|
||||||
const siblingFiles = readdirSync(fullyQualifiedProjectRoot);
|
function writeTargetsToCache(
|
||||||
if (
|
cachePath: string,
|
||||||
!siblingFiles.includes('package.json') &&
|
results: Record<string, RemixTargets>
|
||||||
!siblingFiles.includes('project.json') &&
|
) {
|
||||||
!siblingFiles.includes('vite.config.ts') &&
|
writeJsonFile(cachePath, results);
|
||||||
!siblingFiles.includes('vite.config.js')
|
}
|
||||||
) {
|
|
||||||
return {};
|
/**
|
||||||
|
* @deprecated The 'createDependencies' function is now a no-op. This functionality is included in 'createNodesV2'.
|
||||||
|
*/
|
||||||
|
export const createDependencies: CreateDependencies = () => {
|
||||||
|
return [];
|
||||||
|
};
|
||||||
|
|
||||||
|
const remixConfigGlob = '**/{remix,vite}.config.{js,cjs,mjs}';
|
||||||
|
|
||||||
|
export const createNodesV2: CreateNodesV2<RemixPluginOptions> = [
|
||||||
|
remixConfigGlob,
|
||||||
|
async (configFilePaths, options, context) => {
|
||||||
|
const optionsHash = hashObject(options);
|
||||||
|
const cachePath = join(workspaceDataDirectory, `remix-${optionsHash}.hash`);
|
||||||
|
const targetsCache = readTargetsCache(cachePath);
|
||||||
|
try {
|
||||||
|
return await createNodesFromFiles(
|
||||||
|
(configFile, options, context) =>
|
||||||
|
createNodesInternal(configFile, options, context, targetsCache),
|
||||||
|
configFilePaths,
|
||||||
|
options,
|
||||||
|
context
|
||||||
|
);
|
||||||
|
} finally {
|
||||||
|
writeTargetsToCache(cachePath, targetsCache);
|
||||||
}
|
}
|
||||||
|
|
||||||
options = normalizeOptions(options);
|
|
||||||
|
|
||||||
const hash = await calculateHashForCreateNodes(
|
|
||||||
projectRoot,
|
|
||||||
options,
|
|
||||||
context,
|
|
||||||
[getLockFileName(detectPackageManager(context.workspaceRoot))]
|
|
||||||
);
|
|
||||||
targetsCache[hash] ??= await buildRemixTargets(
|
|
||||||
configFilePath,
|
|
||||||
projectRoot,
|
|
||||||
options,
|
|
||||||
context,
|
|
||||||
siblingFiles
|
|
||||||
);
|
|
||||||
|
|
||||||
return {
|
|
||||||
projects: {
|
|
||||||
[projectRoot]: {
|
|
||||||
root: projectRoot,
|
|
||||||
targets: targetsCache[hash],
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const createNodes: CreateNodes<RemixPluginOptions> = [
|
||||||
|
remixConfigGlob,
|
||||||
|
async (configFilePath, options, context) => {
|
||||||
|
logger.warn(
|
||||||
|
'`createNodes` is deprecated. Update your plugin to utilize createNodesV2 instead. In Nx 20, this will change to the createNodesV2 API.'
|
||||||
|
);
|
||||||
|
return createNodesInternal(configFilePath, options, context, {});
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
async function createNodesInternal(
|
||||||
|
configFilePath: string,
|
||||||
|
options: RemixPluginOptions,
|
||||||
|
context: CreateNodesContext,
|
||||||
|
targetsCache: Record<string, RemixTargets>
|
||||||
|
) {
|
||||||
|
const projectRoot = dirname(configFilePath);
|
||||||
|
const fullyQualifiedProjectRoot = join(context.workspaceRoot, projectRoot);
|
||||||
|
// Do not create a project if package.json and project.json isn't there
|
||||||
|
const siblingFiles = readdirSync(fullyQualifiedProjectRoot);
|
||||||
|
if (
|
||||||
|
!siblingFiles.includes('package.json') &&
|
||||||
|
!siblingFiles.includes('project.json')
|
||||||
|
) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
options = normalizeOptions(options);
|
||||||
|
|
||||||
|
const remixCompiler = determineIsRemixVite(
|
||||||
|
configFilePath,
|
||||||
|
context.workspaceRoot
|
||||||
|
);
|
||||||
|
|
||||||
|
if (remixCompiler === RemixCompiler.IsNotRemix) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const hash =
|
||||||
|
(await calculateHashForCreateNodes(projectRoot, options, context, [
|
||||||
|
getLockFileName(detectPackageManager(context.workspaceRoot)),
|
||||||
|
])) + configFilePath;
|
||||||
|
|
||||||
|
targetsCache[hash] ??= await buildRemixTargets(
|
||||||
|
configFilePath,
|
||||||
|
projectRoot,
|
||||||
|
options,
|
||||||
|
context,
|
||||||
|
siblingFiles,
|
||||||
|
remixCompiler
|
||||||
|
);
|
||||||
|
|
||||||
|
const { targets, metadata } = targetsCache[hash];
|
||||||
|
|
||||||
|
const project: ProjectConfiguration = {
|
||||||
|
root: projectRoot,
|
||||||
|
targets,
|
||||||
|
metadata,
|
||||||
|
};
|
||||||
|
|
||||||
|
return {
|
||||||
|
projects: {
|
||||||
|
[projectRoot]: project,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
async function buildRemixTargets(
|
async function buildRemixTargets(
|
||||||
configFilePath: string,
|
configFilePath: string,
|
||||||
projectRoot: string,
|
projectRoot: string,
|
||||||
options: RemixPluginOptions,
|
options: RemixPluginOptions,
|
||||||
context: CreateNodesContext,
|
context: CreateNodesContext,
|
||||||
siblingFiles: string[]
|
siblingFiles: string[],
|
||||||
|
remixCompiler: RemixCompiler
|
||||||
) {
|
) {
|
||||||
const namedInputs = getNamedInputs(projectRoot, context);
|
const namedInputs = getNamedInputs(projectRoot, context);
|
||||||
const { buildDirectory, assetsBuildDirectory, serverBuildPath } =
|
const { buildDirectory, assetsBuildDirectory, serverBuildPath } =
|
||||||
await getBuildPaths(configFilePath, context.workspaceRoot);
|
await getBuildPaths(
|
||||||
|
configFilePath,
|
||||||
|
projectRoot,
|
||||||
|
context.workspaceRoot,
|
||||||
|
remixCompiler
|
||||||
|
);
|
||||||
|
|
||||||
const targets: Record<string, TargetConfiguration> = {};
|
const targets: Record<string, TargetConfiguration> = {};
|
||||||
targets[options.buildTargetName] = buildTarget(
|
targets[options.buildTargetName] = buildTarget(
|
||||||
@ -112,24 +168,32 @@ async function buildRemixTargets(
|
|||||||
projectRoot,
|
projectRoot,
|
||||||
buildDirectory,
|
buildDirectory,
|
||||||
assetsBuildDirectory,
|
assetsBuildDirectory,
|
||||||
namedInputs
|
namedInputs,
|
||||||
|
remixCompiler
|
||||||
|
);
|
||||||
|
targets[options.devTargetName] = devTarget(
|
||||||
|
serverBuildPath,
|
||||||
|
projectRoot,
|
||||||
|
remixCompiler
|
||||||
);
|
);
|
||||||
targets[options.devTargetName] = devTarget(serverBuildPath, projectRoot);
|
|
||||||
targets[options.startTargetName] = startTarget(
|
targets[options.startTargetName] = startTarget(
|
||||||
projectRoot,
|
projectRoot,
|
||||||
serverBuildPath,
|
serverBuildPath,
|
||||||
options.buildTargetName
|
options.buildTargetName,
|
||||||
|
remixCompiler
|
||||||
);
|
);
|
||||||
// TODO(colum): Remove for Nx 21
|
// TODO(colum): Remove for Nx 21
|
||||||
targets[options.staticServeTargetName] = startTarget(
|
targets[options.staticServeTargetName] = startTarget(
|
||||||
projectRoot,
|
projectRoot,
|
||||||
serverBuildPath,
|
serverBuildPath,
|
||||||
options.buildTargetName
|
options.buildTargetName,
|
||||||
|
remixCompiler
|
||||||
);
|
);
|
||||||
targets[options.serveStaticTargetName] = startTarget(
|
targets[options.serveStaticTargetName] = startTarget(
|
||||||
projectRoot,
|
projectRoot,
|
||||||
serverBuildPath,
|
serverBuildPath,
|
||||||
options.buildTargetName
|
options.buildTargetName,
|
||||||
|
remixCompiler
|
||||||
);
|
);
|
||||||
targets[options.typecheckTargetName] = typecheckTarget(
|
targets[options.typecheckTargetName] = typecheckTarget(
|
||||||
projectRoot,
|
projectRoot,
|
||||||
@ -137,7 +201,7 @@ async function buildRemixTargets(
|
|||||||
siblingFiles
|
siblingFiles
|
||||||
);
|
);
|
||||||
|
|
||||||
return targets;
|
return { targets, metadata: {} };
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildTarget(
|
function buildTarget(
|
||||||
@ -145,7 +209,8 @@ function buildTarget(
|
|||||||
projectRoot: string,
|
projectRoot: string,
|
||||||
buildDirectory: string,
|
buildDirectory: string,
|
||||||
assetsBuildDirectory: string,
|
assetsBuildDirectory: string,
|
||||||
namedInputs: { [inputName: string]: any[] }
|
namedInputs: { [inputName: string]: any[] },
|
||||||
|
remixCompiler: RemixCompiler
|
||||||
): TargetConfiguration {
|
): TargetConfiguration {
|
||||||
const serverBuildOutputPath =
|
const serverBuildOutputPath =
|
||||||
projectRoot === '.'
|
projectRoot === '.'
|
||||||
@ -157,6 +222,15 @@ function buildTarget(
|
|||||||
? joinPathFragments(`{workspaceRoot}`, assetsBuildDirectory)
|
? joinPathFragments(`{workspaceRoot}`, assetsBuildDirectory)
|
||||||
: joinPathFragments(`{workspaceRoot}`, projectRoot, assetsBuildDirectory);
|
: joinPathFragments(`{workspaceRoot}`, projectRoot, assetsBuildDirectory);
|
||||||
|
|
||||||
|
const outputs =
|
||||||
|
remixCompiler === RemixCompiler.IsVte
|
||||||
|
? [
|
||||||
|
projectRoot === '.'
|
||||||
|
? joinPathFragments(`{workspaceRoot}`, buildDirectory)
|
||||||
|
: joinPathFragments(`{workspaceRoot}`, projectRoot, buildDirectory),
|
||||||
|
]
|
||||||
|
: [serverBuildOutputPath, assetsBuildOutputPath];
|
||||||
|
|
||||||
return {
|
return {
|
||||||
cache: true,
|
cache: true,
|
||||||
dependsOn: [`^${buildTargetName}`],
|
dependsOn: [`^${buildTargetName}`],
|
||||||
@ -166,18 +240,25 @@ function buildTarget(
|
|||||||
: ['default', '^default']),
|
: ['default', '^default']),
|
||||||
{ externalDependencies: ['@remix-run/dev'] },
|
{ externalDependencies: ['@remix-run/dev'] },
|
||||||
],
|
],
|
||||||
outputs: [serverBuildOutputPath, assetsBuildOutputPath],
|
outputs,
|
||||||
command: 'remix build',
|
command:
|
||||||
|
remixCompiler === RemixCompiler.IsVte
|
||||||
|
? 'remix vite:build'
|
||||||
|
: 'remix build',
|
||||||
options: { cwd: projectRoot },
|
options: { cwd: projectRoot },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function devTarget(
|
function devTarget(
|
||||||
serverBuildPath: string,
|
serverBuildPath: string,
|
||||||
projectRoot: string
|
projectRoot: string,
|
||||||
|
remixCompiler: RemixCompiler
|
||||||
): TargetConfiguration {
|
): TargetConfiguration {
|
||||||
return {
|
return {
|
||||||
command: 'remix dev --manual',
|
command:
|
||||||
|
remixCompiler === RemixCompiler.IsVte
|
||||||
|
? 'remix vite:dev'
|
||||||
|
: 'remix dev --manual',
|
||||||
options: { cwd: projectRoot },
|
options: { cwd: projectRoot },
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -185,11 +266,19 @@ function devTarget(
|
|||||||
function startTarget(
|
function startTarget(
|
||||||
projectRoot: string,
|
projectRoot: string,
|
||||||
serverBuildPath: string,
|
serverBuildPath: string,
|
||||||
buildTargetName: string
|
buildTargetName: string,
|
||||||
|
remixCompiler: RemixCompiler
|
||||||
): TargetConfiguration {
|
): TargetConfiguration {
|
||||||
|
let serverPath = serverBuildPath;
|
||||||
|
if (remixCompiler === RemixCompiler.IsVte) {
|
||||||
|
if (serverBuildPath === 'build') {
|
||||||
|
serverPath = `${serverBuildPath}/server/index.js`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
dependsOn: [buildTargetName],
|
dependsOn: [buildTargetName],
|
||||||
command: `remix-serve ${serverBuildPath}`,
|
command: `remix-serve ${serverPath}`,
|
||||||
options: {
|
options: {
|
||||||
cwd: projectRoot,
|
cwd: projectRoot,
|
||||||
},
|
},
|
||||||
@ -222,19 +311,46 @@ function typecheckTarget(
|
|||||||
|
|
||||||
async function getBuildPaths(
|
async function getBuildPaths(
|
||||||
configFilePath: string,
|
configFilePath: string,
|
||||||
workspaceRoot: string
|
projectRoot: string,
|
||||||
|
workspaceRoot: string,
|
||||||
|
remixCompiler: RemixCompiler
|
||||||
): Promise<{
|
): Promise<{
|
||||||
buildDirectory: string;
|
buildDirectory: string;
|
||||||
assetsBuildDirectory: string;
|
assetsBuildDirectory?: string;
|
||||||
serverBuildPath: string;
|
serverBuildPath?: string;
|
||||||
}> {
|
}> {
|
||||||
const configPath = join(workspaceRoot, configFilePath);
|
const configPath = join(workspaceRoot, configFilePath);
|
||||||
let appConfig = await loadConfigFile<AppConfig>(configPath);
|
if (remixCompiler === RemixCompiler.IsClassic) {
|
||||||
return {
|
let appConfig = await loadConfigFile<AppConfig>(configPath);
|
||||||
buildDirectory: 'build',
|
return {
|
||||||
serverBuildPath: appConfig.serverBuildPath ?? 'build/index.js',
|
buildDirectory: 'build',
|
||||||
assetsBuildDirectory: appConfig.assetsBuildDirectory ?? 'public/build',
|
serverBuildPath: appConfig.serverBuildPath ?? 'build/index.js',
|
||||||
};
|
assetsBuildDirectory: appConfig.assetsBuildDirectory ?? 'public/build',
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
// Workaround for the `build$3 is not a function` error that we sometimes see in agents.
|
||||||
|
// This should be removed later once we address the issue properly
|
||||||
|
try {
|
||||||
|
const importEsbuild = () => new Function('return import("esbuild")')();
|
||||||
|
await importEsbuild();
|
||||||
|
} catch {
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
const { resolveConfig } = await loadViteDynamicImport();
|
||||||
|
const viteBuildConfig = await resolveConfig(
|
||||||
|
{
|
||||||
|
configFile: configPath,
|
||||||
|
mode: 'development',
|
||||||
|
},
|
||||||
|
'build'
|
||||||
|
);
|
||||||
|
|
||||||
|
return {
|
||||||
|
buildDirectory: viteBuildConfig.build?.outDir ?? 'build',
|
||||||
|
serverBuildPath: viteBuildConfig.build?.outDir ?? 'build',
|
||||||
|
assetsBuildDirectory: 'build/client',
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function normalizeOptions(options: RemixPluginOptions) {
|
function normalizeOptions(options: RemixPluginOptions) {
|
||||||
@ -249,3 +365,28 @@ function normalizeOptions(options: RemixPluginOptions) {
|
|||||||
|
|
||||||
return options;
|
return options;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function determineIsRemixVite(configFilePath: string, workspaceRoot: string) {
|
||||||
|
if (configFilePath.includes('remix.config')) {
|
||||||
|
return RemixCompiler.IsClassic;
|
||||||
|
}
|
||||||
|
|
||||||
|
const fileContents = readFileSync(
|
||||||
|
join(workspaceRoot, configFilePath),
|
||||||
|
'utf8'
|
||||||
|
);
|
||||||
|
if (
|
||||||
|
fileContents.includes('@remix-run/dev') &&
|
||||||
|
(fileContents.includes('vitePlugin()') || fileContents.includes('remix()'))
|
||||||
|
) {
|
||||||
|
return RemixCompiler.IsVte;
|
||||||
|
} else {
|
||||||
|
return RemixCompiler.IsNotRemix;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum RemixCompiler {
|
||||||
|
IsClassic = 1,
|
||||||
|
IsVte = 2,
|
||||||
|
IsNotRemix = 3,
|
||||||
|
}
|
||||||
|
|||||||
3
packages/remix/src/utils/executor-utils.ts
Normal file
3
packages/remix/src/utils/executor-utils.ts
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
export function loadViteDynamicImport() {
|
||||||
|
return Function('return import("vite")')() as Promise<typeof import('vite')>;
|
||||||
|
}
|
||||||
@ -83,6 +83,7 @@ describe('@nx/vite:init', () => {
|
|||||||
"serveStaticTargetName": "serve-static",
|
"serveStaticTargetName": "serve-static",
|
||||||
"serveTargetName": "serve",
|
"serveTargetName": "serve",
|
||||||
"testTargetName": "test",
|
"testTargetName": "test",
|
||||||
|
"typecheckTargetName": "typecheck",
|
||||||
},
|
},
|
||||||
"plugin": "@nx/vite/plugin",
|
"plugin": "@nx/vite/plugin",
|
||||||
},
|
},
|
||||||
|
|||||||
@ -76,6 +76,7 @@ export async function initGeneratorInternal(
|
|||||||
'vite:serve-static',
|
'vite:serve-static',
|
||||||
'vite-serve-static',
|
'vite-serve-static',
|
||||||
],
|
],
|
||||||
|
typecheckTargetName: ['typecheck', 'vite:typecheck', 'vite-typecheck'],
|
||||||
},
|
},
|
||||||
schema.updatePackageScripts
|
schema.updatePackageScripts
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user