rails-vite-plugin 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +24 -10
- package/dist/jsbundling.js +22 -11
- package/dist/shared/bundler-compat.d.ts +5 -0
- package/dist/shared/bundler-compat.js +9 -0
- package/dist/shared/dev-server.d.ts +1 -0
- package/dist/shared/dev-server.js +6 -0
- package/dist/shared/types.d.ts +1 -0
- package/dist/shared/types.js +3 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2,9 +2,11 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import picomatch from 'picomatch';
|
|
4
4
|
import { loadEnv, defaultAllowedOrigins, } from 'vite';
|
|
5
|
+
import { ORIGIN_PLACEHOLDER } from './shared/types.js';
|
|
5
6
|
import { resolveInput, detectEntrypointsDir, discoverEntrypointInputs, detectEntrypoint } from './shared/entries.js';
|
|
6
7
|
import { resolveAlias } from './shared/alias.js';
|
|
7
|
-
import { resolveDevServerUrl, isAddressInfo } from './shared/dev-server.js';
|
|
8
|
+
import { resolveDevServerUrl, isAddressInfo, replaceOriginPlaceholder } from './shared/dev-server.js';
|
|
9
|
+
import { resolveBundlerOptionsKey, getUserBundlerInput } from './shared/bundler-compat.js';
|
|
8
10
|
import { ensureCommandShouldRunInEnvironment } from './shared/env-guard.js';
|
|
9
11
|
import { refreshPaths, resolveRefreshPaths } from './shared/refresh.js';
|
|
10
12
|
import { readDevServerIndexHtml } from './shared/dev-server-page.js';
|
|
@@ -16,32 +18,39 @@ export default function rails(options = {}) {
|
|
|
16
18
|
const entrypointsDir = options.input === undefined ? detectEntrypointsDir(sourceDir) : null;
|
|
17
19
|
const input = options.input ?? (entrypointsDir ? discoverEntrypointInputs(sourceDir, entrypointsDir) : detectEntrypoint(sourceDir));
|
|
18
20
|
const publicDir = options.publicDir ?? 'public';
|
|
19
|
-
const
|
|
21
|
+
const userBuildDir = options.buildDir;
|
|
20
22
|
const devMetaPath = options.devMetaFile ?? path.join('tmp', 'rails-vite.json');
|
|
21
23
|
const ssrOutDir = options.ssrOutDir ?? 'ssr';
|
|
22
24
|
const resolvedInput = resolveInput(input, sourceDir);
|
|
23
25
|
const resolvedSsr = options.ssr !== undefined ? resolveInput(options.ssr, sourceDir) : undefined;
|
|
24
26
|
let resolvedConfig;
|
|
25
27
|
let reactRefresh = false;
|
|
28
|
+
let devServerUrl = null;
|
|
29
|
+
let effectiveBuildDir;
|
|
26
30
|
return {
|
|
27
31
|
name: 'rails-vite',
|
|
28
32
|
enforce: 'post',
|
|
29
33
|
config(userConfig, { command, mode, isSsrBuild }) {
|
|
30
34
|
const env = loadEnv(mode, userConfig.envDir || process.cwd(), '');
|
|
31
35
|
ensureCommandShouldRunInEnvironment(command, env, 'rails-vite-plugin');
|
|
36
|
+
// @ts-expect-error -- `this.meta.rolldownVersion` exists in Vite 8+
|
|
37
|
+
const bundlerOptionsKey = resolveBundlerOptionsKey(this.meta);
|
|
38
|
+
const userBundlerInput = getUserBundlerInput(userConfig);
|
|
39
|
+
effectiveBuildDir = userBuildDir ?? (mode === 'test' ? 'vite-test' : 'vite');
|
|
32
40
|
return {
|
|
33
|
-
base: userConfig.base ?? (command === 'build' ? `/${
|
|
41
|
+
base: userConfig.base ?? (command === 'build' ? `/${effectiveBuildDir}/` : ''),
|
|
34
42
|
publicDir: userConfig.publicDir ?? false,
|
|
35
43
|
build: {
|
|
36
44
|
manifest: userConfig.build?.manifest ?? (isSsrBuild ? false : 'manifest.json'),
|
|
37
45
|
ssrManifest: userConfig.build?.ssrManifest ?? (isSsrBuild ? 'ssr-manifest.json' : false),
|
|
38
|
-
outDir: userConfig.build?.outDir ?? (isSsrBuild ? ssrOutDir : path.join(publicDir,
|
|
39
|
-
|
|
40
|
-
input:
|
|
46
|
+
outDir: userConfig.build?.outDir ?? (isSsrBuild ? ssrOutDir : path.join(publicDir, effectiveBuildDir)),
|
|
47
|
+
[bundlerOptionsKey]: {
|
|
48
|
+
input: userBundlerInput ?? (isSsrBuild ? resolvedSsr : resolvedInput),
|
|
41
49
|
},
|
|
42
50
|
assetsInlineLimit: userConfig.build?.assetsInlineLimit ?? 0,
|
|
43
51
|
},
|
|
44
52
|
server: {
|
|
53
|
+
origin: command === 'serve' ? (userConfig.server?.origin ?? ORIGIN_PLACEHOLDER) : undefined,
|
|
45
54
|
cors: userConfig.server?.cors ?? {
|
|
46
55
|
origin: userConfig.server?.origin ?? defaultAllowedOrigins,
|
|
47
56
|
},
|
|
@@ -62,15 +71,20 @@ export default function rails(options = {}) {
|
|
|
62
71
|
if (resolvedConfig.build.ssr)
|
|
63
72
|
return;
|
|
64
73
|
const outDir = resolvedConfig.build.outDir;
|
|
65
|
-
|
|
74
|
+
const meta = { sourceDir, buildDir: effectiveBuildDir };
|
|
75
|
+
if (entrypointsDir)
|
|
76
|
+
meta.entrypointsDir = entrypointsDir;
|
|
77
|
+
fs.writeFileSync(path.join(outDir, 'rails-vite.json'), JSON.stringify(meta));
|
|
78
|
+
},
|
|
79
|
+
transform(code) {
|
|
80
|
+
return replaceOriginPlaceholder(code, devServerUrl);
|
|
66
81
|
},
|
|
67
82
|
configureServer(server) {
|
|
68
83
|
server.httpServer?.once('listening', () => {
|
|
69
84
|
const address = server.httpServer?.address();
|
|
70
85
|
if (isAddressInfo(address)) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
const meta = { url: devServerUrl, sourceDir };
|
|
86
|
+
devServerUrl = resolveDevServerUrl(address, resolvedConfig);
|
|
87
|
+
const meta = { url: devServerUrl, sourceDir, buildDir: effectiveBuildDir };
|
|
74
88
|
if (entrypointsDir)
|
|
75
89
|
meta.entrypointsDir = entrypointsDir;
|
|
76
90
|
if (reactRefresh)
|
package/dist/jsbundling.js
CHANGED
|
@@ -2,9 +2,11 @@ import fs from 'fs';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import picomatch from 'picomatch';
|
|
4
4
|
import { loadEnv, defaultAllowedOrigins, } from 'vite';
|
|
5
|
+
import { ORIGIN_PLACEHOLDER } from './shared/types.js';
|
|
5
6
|
import { resolveEntries, entriesToRollupInput, prefixWithSourceDir, detectEntrypointsDir, discoverEntrypointInputs, detectEntrypoint, isEntrypointFile } from './shared/entries.js';
|
|
6
7
|
import { resolveAlias } from './shared/alias.js';
|
|
7
|
-
import { resolveDevServerUrl, isAddressInfo } from './shared/dev-server.js';
|
|
8
|
+
import { resolveDevServerUrl, isAddressInfo, replaceOriginPlaceholder } from './shared/dev-server.js';
|
|
9
|
+
import { resolveBundlerOptionsKey, getUserBundlerInput } from './shared/bundler-compat.js';
|
|
8
10
|
import { ensureCommandShouldRunInEnvironment } from './shared/env-guard.js';
|
|
9
11
|
import { refreshPaths, resolveRefreshPaths } from './shared/refresh.js';
|
|
10
12
|
import { cssExtensions } from './shared/css.js';
|
|
@@ -30,6 +32,7 @@ export default function jsbundling(options = {}) {
|
|
|
30
32
|
const ssrConfig = resolveSsrConfig(options.ssr, sourceDir, outputDir);
|
|
31
33
|
let resolvedConfig;
|
|
32
34
|
let reactRefresh = false;
|
|
35
|
+
let devServerUrl = null;
|
|
33
36
|
// Track stubs written in dev so we can clean them up
|
|
34
37
|
const writtenStubs = [];
|
|
35
38
|
return {
|
|
@@ -38,6 +41,9 @@ export default function jsbundling(options = {}) {
|
|
|
38
41
|
config(userConfig, { command, mode, isSsrBuild }) {
|
|
39
42
|
const env = loadEnv(mode, userConfig.envDir || process.cwd(), '');
|
|
40
43
|
ensureCommandShouldRunInEnvironment(command, env, 'rails-vite-plugin/jsbundling');
|
|
44
|
+
// @ts-expect-error -- `this.meta.rolldownVersion` exists in Vite 8+
|
|
45
|
+
const bundlerOptionsKey = resolveBundlerOptionsKey(this.meta);
|
|
46
|
+
const userBundlerInput = getUserBundlerInput(userConfig);
|
|
41
47
|
// SSR builds get minimal config — just entry, outDir, base, and alias.
|
|
42
48
|
// No asset pipeline stubs or client-specific settings.
|
|
43
49
|
if (isSsrBuild) {
|
|
@@ -48,8 +54,8 @@ export default function jsbundling(options = {}) {
|
|
|
48
54
|
build: {
|
|
49
55
|
ssrManifest: userConfig.build?.ssrManifest ?? 'ssr-manifest.json',
|
|
50
56
|
outDir: userConfig.build?.outDir ?? ssrConfig.outDir,
|
|
51
|
-
|
|
52
|
-
input:
|
|
57
|
+
[bundlerOptionsKey]: {
|
|
58
|
+
input: userBundlerInput ?? ssrConfig.entry,
|
|
53
59
|
},
|
|
54
60
|
},
|
|
55
61
|
} : {}),
|
|
@@ -61,19 +67,14 @@ export default function jsbundling(options = {}) {
|
|
|
61
67
|
},
|
|
62
68
|
};
|
|
63
69
|
}
|
|
64
|
-
// In dev mode, write placeholder stubs immediately so Propshaft/Sprockets
|
|
65
|
-
// can discover them when Rails boots (both may start concurrently via bin/dev).
|
|
66
|
-
if (command === 'serve') {
|
|
67
|
-
writePlaceholderStubs(entries, assetPipelineDir, writtenStubs);
|
|
68
|
-
}
|
|
69
70
|
return {
|
|
70
71
|
base: userConfig.base ?? (command === 'build' ? buildBase : ''),
|
|
71
72
|
publicDir: userConfig.publicDir ?? false,
|
|
72
73
|
build: {
|
|
73
74
|
manifest: userConfig.build?.manifest ?? false,
|
|
74
75
|
outDir: userConfig.build?.outDir ?? outputDir,
|
|
75
|
-
|
|
76
|
-
input:
|
|
76
|
+
[bundlerOptionsKey]: {
|
|
77
|
+
input: userBundlerInput ?? rollupInput,
|
|
77
78
|
output: {
|
|
78
79
|
entryFileNames: (chunkInfo) => {
|
|
79
80
|
if (chunkInfo.facadeModuleId && cssExtensions.test(chunkInfo.facadeModuleId)) {
|
|
@@ -89,6 +90,7 @@ export default function jsbundling(options = {}) {
|
|
|
89
90
|
cssCodeSplit: true,
|
|
90
91
|
},
|
|
91
92
|
server: {
|
|
93
|
+
origin: command === 'serve' ? (userConfig.server?.origin ?? ORIGIN_PLACEHOLDER) : undefined,
|
|
92
94
|
cors: userConfig.server?.cors ?? {
|
|
93
95
|
origin: userConfig.server?.origin ?? defaultAllowedOrigins,
|
|
94
96
|
},
|
|
@@ -138,8 +140,10 @@ export default function jsbundling(options = {}) {
|
|
|
138
140
|
}
|
|
139
141
|
}
|
|
140
142
|
},
|
|
143
|
+
transform(code) {
|
|
144
|
+
return replaceOriginPlaceholder(code, devServerUrl);
|
|
145
|
+
},
|
|
141
146
|
configureServer(server) {
|
|
142
|
-
let devServerUrl = null;
|
|
143
147
|
let syncTimer = null;
|
|
144
148
|
// Re-discover entries from the entrypoints dir and regenerate all stubs.
|
|
145
149
|
// Called on initial listen and whenever entrypoint files are added/removed.
|
|
@@ -162,6 +166,13 @@ export default function jsbundling(options = {}) {
|
|
|
162
166
|
clearTimeout(syncTimer);
|
|
163
167
|
syncTimer = setTimeout(syncStubs, 100);
|
|
164
168
|
};
|
|
169
|
+
// Write placeholder stubs so Propshaft/Sprockets can discover asset files
|
|
170
|
+
// at boot time, before the Vite dev server is ready with its URL.
|
|
171
|
+
// Only write when httpServer exists — skip for embedded Vite instances
|
|
172
|
+
// (e.g., Storybook) that would otherwise overwrite real dev stubs.
|
|
173
|
+
if (server.httpServer && !server.httpServer.listening) {
|
|
174
|
+
writePlaceholderStubs(entries, assetPipelineDir, writtenStubs);
|
|
175
|
+
}
|
|
165
176
|
server.httpServer?.once('listening', () => {
|
|
166
177
|
const address = server.httpServer?.address();
|
|
167
178
|
if (isAddressInfo(address)) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Vite 8 (Rolldown) uses `rolldownOptions` instead of `rollupOptions`.
|
|
2
|
+
// Detect at runtime to support both Vite 7 and 8.
|
|
3
|
+
export function resolveBundlerOptionsKey(meta) {
|
|
4
|
+
return meta?.rolldownVersion ? 'rolldownOptions' : 'rollupOptions';
|
|
5
|
+
}
|
|
6
|
+
export function getUserBundlerInput(userConfig) {
|
|
7
|
+
// @ts-expect-error -- `rolldownOptions` exists in Vite 8+ only
|
|
8
|
+
return userConfig.build?.rolldownOptions?.input ?? userConfig.build?.rollupOptions?.input;
|
|
9
|
+
}
|
|
@@ -3,3 +3,4 @@ import type { ResolvedConfig } from 'vite';
|
|
|
3
3
|
import type { DevServerUrl } from './types.js';
|
|
4
4
|
export declare function resolveDevServerUrl(address: AddressInfo, config: ResolvedConfig): DevServerUrl;
|
|
5
5
|
export declare function isAddressInfo(x: string | AddressInfo | null | undefined): x is AddressInfo;
|
|
6
|
+
export declare function replaceOriginPlaceholder(code: string, devServerUrl: string | null): string | undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { ORIGIN_PLACEHOLDER } from './types.js';
|
|
1
2
|
export function resolveDevServerUrl(address, config) {
|
|
2
3
|
const hmr = typeof config.server.hmr === 'object' ? config.server.hmr : null;
|
|
3
4
|
const clientProtocol = hmr?.protocol
|
|
@@ -18,3 +19,8 @@ export function resolveDevServerUrl(address, config) {
|
|
|
18
19
|
export function isAddressInfo(x) {
|
|
19
20
|
return typeof x === 'object' && x !== null;
|
|
20
21
|
}
|
|
22
|
+
export function replaceOriginPlaceholder(code, devServerUrl) {
|
|
23
|
+
if (devServerUrl && code.includes(ORIGIN_PLACEHOLDER)) {
|
|
24
|
+
return code.replaceAll(ORIGIN_PLACEHOLDER, devServerUrl);
|
|
25
|
+
}
|
|
26
|
+
}
|
package/dist/shared/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export type InputOption = string | string[] | Record<string, string>;
|
|
2
2
|
export type DevServerUrl = `${'http' | 'https'}://${string}:${number}`;
|
|
3
|
+
export declare const ORIGIN_PLACEHOLDER = "http://__rails_vite_placeholder__.test";
|
|
3
4
|
export interface ResolvedEntry {
|
|
4
5
|
/** Output name (e.g., 'application', 'admin/index') */
|
|
5
6
|
name: string;
|
package/dist/shared/types.js
CHANGED