fix(vite): environments api support in executor (#30183)
## Current Behavior `@nx/vite:build` executor does not support Vite 6 Environments API ## Expected Behavior `@nx/vite:build` executor builds all environments when Vite 6 is detected
This commit is contained in:
parent
320709f66f
commit
6fcb310e54
@ -58,6 +58,12 @@
|
|||||||
"skipPackageManager": {
|
"skipPackageManager": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
"description": "Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||||
|
},
|
||||||
|
"useEnvironmentsApi": {
|
||||||
|
"alias": "app",
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Use the new Environments API for building multiple environments at once. Only works with Vite 6.0.0 or higher.",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {},
|
"definitions": {},
|
||||||
|
|||||||
@ -89,6 +89,103 @@ describe('Vite Plugin', () => {
|
|||||||
}, 200_000);
|
}, 200_000);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('set up new React app with --bundler=vite option and use environments api', () => {
|
||||||
|
let myApp;
|
||||||
|
|
||||||
|
beforeAll(() => {
|
||||||
|
myApp = uniq('my-app');
|
||||||
|
runCLI(
|
||||||
|
`generate @nx/react:app ${myApp} --bundler=vite --unitTestRunner=vitest`
|
||||||
|
);
|
||||||
|
updateJson(`${myApp}/project.json`, (json) => {
|
||||||
|
json.targets.build.options.useEnvironmentsApi = true;
|
||||||
|
return json;
|
||||||
|
});
|
||||||
|
updateFile(
|
||||||
|
`${myApp}/vite.config.ts`,
|
||||||
|
`/// <reference types='vitest' />
|
||||||
|
import { defineConfig } from 'vite';
|
||||||
|
import react from '@vitejs/plugin-react';
|
||||||
|
import { nxViteTsPaths } from '@nx/vite/plugins/nx-tsconfig-paths.plugin';
|
||||||
|
import { nxCopyAssetsPlugin } from '@nx/vite/plugins/nx-copy-assets.plugin';
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
root: __dirname,
|
||||||
|
cacheDir: './node_modules/.vite/${myApp}',
|
||||||
|
server: {
|
||||||
|
port: 4200,
|
||||||
|
host: 'localhost',
|
||||||
|
},
|
||||||
|
preview: {
|
||||||
|
port: 4300,
|
||||||
|
host: 'localhost',
|
||||||
|
},
|
||||||
|
plugins: [react(), nxViteTsPaths(), nxCopyAssetsPlugin(['*.md'])],
|
||||||
|
// Uncomment this if you are using workers.
|
||||||
|
// worker: {
|
||||||
|
// plugins: [ nxViteTsPaths() ],
|
||||||
|
// },
|
||||||
|
builder: {},
|
||||||
|
environments: {
|
||||||
|
ssr: {
|
||||||
|
build: {
|
||||||
|
rollupOptions: {
|
||||||
|
input: '${myApp}/src/main.server.tsx'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
build: {
|
||||||
|
outDir: './dist/${myApp}',
|
||||||
|
emptyOutDir: false,
|
||||||
|
reportCompressedSize: true,
|
||||||
|
commonjsOptions: {
|
||||||
|
transformMixedEsModules: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
test: {
|
||||||
|
watch: false,
|
||||||
|
globals: true,
|
||||||
|
environment: 'jsdom',
|
||||||
|
include: ['src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}'],
|
||||||
|
reporters: ['default'],
|
||||||
|
coverage: {
|
||||||
|
reportsDirectory: './coverage/${myApp}',
|
||||||
|
provider: 'v8',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
`
|
||||||
|
);
|
||||||
|
updateFile(
|
||||||
|
`${myApp}/src/main.server.tsx`,
|
||||||
|
`import React from 'react'
|
||||||
|
import ReactDOMServer from 'react-dom/server'
|
||||||
|
import App from './app/app';
|
||||||
|
|
||||||
|
export default async function render(_url: string, document: string) {
|
||||||
|
const html = ReactDOMServer.renderToString(
|
||||||
|
<React.StrictMode>
|
||||||
|
<App />
|
||||||
|
</React.StrictMode>
|
||||||
|
)
|
||||||
|
return document.replace('<!--app-html-->', html);
|
||||||
|
}`
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
rmDist();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should build application', async () => {
|
||||||
|
runCLI(`build ${myApp}`);
|
||||||
|
expect(readFile(`dist/${myApp}/favicon.ico`)).toBeDefined();
|
||||||
|
expect(readFile(`dist/${myApp}/index.html`)).toBeDefined();
|
||||||
|
expect(readFile(`dist/${myApp}/main.server.mjs`)).toBeDefined();
|
||||||
|
}, 200_000);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('Vite on Web apps', () => {
|
describe('Vite on Web apps', () => {
|
||||||
|
|||||||
@ -20,7 +20,10 @@ import {
|
|||||||
} from '@nx/js';
|
} from '@nx/js';
|
||||||
import { existsSync, writeFileSync } from 'fs';
|
import { existsSync, writeFileSync } from 'fs';
|
||||||
import { relative, resolve } from 'path';
|
import { relative, resolve } from 'path';
|
||||||
import { createAsyncIterable } from '@nx/devkit/src/utils/async-iterable';
|
import {
|
||||||
|
combineAsyncIterables,
|
||||||
|
createAsyncIterable,
|
||||||
|
} from '@nx/devkit/src/utils/async-iterable';
|
||||||
import {
|
import {
|
||||||
createBuildableTsConfig,
|
createBuildableTsConfig,
|
||||||
loadViteDynamicImport,
|
loadViteDynamicImport,
|
||||||
@ -35,7 +38,8 @@ export async function* viteBuildExecutor(
|
|||||||
) {
|
) {
|
||||||
process.env.VITE_CJS_IGNORE_WARNING = 'true';
|
process.env.VITE_CJS_IGNORE_WARNING = 'true';
|
||||||
// Allows ESM to be required in CJS modules. Vite will be published as ESM in the future.
|
// Allows ESM to be required in CJS modules. Vite will be published as ESM in the future.
|
||||||
const { mergeConfig, build, resolveConfig } = await loadViteDynamicImport();
|
const { mergeConfig, build, resolveConfig, createBuilder } =
|
||||||
|
await loadViteDynamicImport();
|
||||||
const projectRoot =
|
const projectRoot =
|
||||||
context.projectsConfigurations.projects[context.projectName].root;
|
context.projectsConfigurations.projects[context.projectName].root;
|
||||||
const tsConfigForBuild = createBuildableTsConfig(
|
const tsConfigForBuild = createBuildableTsConfig(
|
||||||
@ -50,7 +54,7 @@ export async function* viteBuildExecutor(
|
|||||||
options.configFile
|
options.configFile
|
||||||
);
|
);
|
||||||
const root =
|
const root =
|
||||||
projectRoot === '.'
|
projectRoot === '.' || projectRoot === ''
|
||||||
? process.cwd()
|
? process.cwd()
|
||||||
: relative(context.cwd, joinPathFragments(context.root, projectRoot));
|
: relative(context.cwd, joinPathFragments(context.root, projectRoot));
|
||||||
|
|
||||||
@ -100,7 +104,25 @@ export async function* viteBuildExecutor(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
const watcherOrOutput = await build(buildConfig);
|
const builder =
|
||||||
|
createBuilder !== undefined && options.useEnvironmentsApi
|
||||||
|
? await createBuilder(buildConfig)
|
||||||
|
: // This is needed to ensure support for Vite 5
|
||||||
|
{
|
||||||
|
build: (inlineConfig) => build(inlineConfig),
|
||||||
|
environments: { build: buildConfig },
|
||||||
|
};
|
||||||
|
|
||||||
|
let iterables: AsyncIterable<{ success: boolean; outfile?: string }>[] = [];
|
||||||
|
for (const env of Object.values(builder.environments)) {
|
||||||
|
// This is needed to overwrite the resolve build config with executor options in Vite 6
|
||||||
|
if (env.config?.build) {
|
||||||
|
env.config.build = {
|
||||||
|
...env.config.build,
|
||||||
|
...buildConfig.build,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
const watcherOrOutput = await builder.build(env as any);
|
||||||
|
|
||||||
const libraryPackageJson = resolve(projectRoot, 'package.json');
|
const libraryPackageJson = resolve(projectRoot, 'package.json');
|
||||||
const rootPackageJson = resolve(context.root, 'package.json');
|
const rootPackageJson = resolve(context.root, 'package.json');
|
||||||
@ -177,8 +199,11 @@ export async function* viteBuildExecutor(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const iterable = createAsyncIterable<{
|
||||||
|
success: boolean;
|
||||||
|
outfile?: string;
|
||||||
|
}>(({ next, done }) => {
|
||||||
if ('on' in watcherOrOutput) {
|
if ('on' in watcherOrOutput) {
|
||||||
const iterable = createAsyncIterable<{ success: boolean }>(({ next }) => {
|
|
||||||
let success = true;
|
let success = true;
|
||||||
watcherOrOutput.on('event', (event) => {
|
watcherOrOutput.on('event', (event) => {
|
||||||
if (event.code === 'START') {
|
if (event.code === 'START') {
|
||||||
@ -194,14 +219,18 @@ export async function* viteBuildExecutor(
|
|||||||
event.result.close();
|
event.result.close();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
|
||||||
yield* iterable;
|
|
||||||
} else {
|
} else {
|
||||||
const output = watcherOrOutput?.['output'] || watcherOrOutput?.[0]?.output;
|
const output =
|
||||||
|
watcherOrOutput?.['output'] || watcherOrOutput?.[0]?.output;
|
||||||
const fileName = output?.[0]?.fileName || 'main.cjs';
|
const fileName = output?.[0]?.fileName || 'main.cjs';
|
||||||
const outfile = resolve(outDirRelativeToWorkspaceRoot, fileName);
|
const outfile = resolve(outDirRelativeToWorkspaceRoot, fileName);
|
||||||
yield { success: true, outfile };
|
next({ success: true, outfile });
|
||||||
|
done();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
iterables.push(iterable);
|
||||||
|
}
|
||||||
|
return yield* combineAsyncIterables(iterables.shift(), ...(iterables ?? []));
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getBuildExtraArgs(
|
export async function getBuildExtraArgs(
|
||||||
|
|||||||
@ -9,4 +9,5 @@ export interface ViteBuildExecutorOptions {
|
|||||||
skipTypeCheck?: boolean;
|
skipTypeCheck?: boolean;
|
||||||
tsConfig?: string;
|
tsConfig?: string;
|
||||||
watch?: boolean;
|
watch?: boolean;
|
||||||
|
useEnvironmentsApi?: boolean;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -67,6 +67,12 @@
|
|||||||
"skipPackageManager": {
|
"skipPackageManager": {
|
||||||
"type": "boolean",
|
"type": "boolean",
|
||||||
"description": "Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
"description": "Do not add a `packageManager` entry to the generated package.json file. Only works in conjunction with `generatePackageJson` option."
|
||||||
|
},
|
||||||
|
"useEnvironmentsApi": {
|
||||||
|
"alias": "app",
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Use the new Environments API for building multiple environments at once. Only works with Vite 6.0.0 or higher.",
|
||||||
|
"default": false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"definitions": {},
|
"definitions": {},
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user