rails-vite-plugin 0.1.0-beta.1 → 0.1.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/dev-server-index.html +185 -5
- package/dist/index.d.ts +4 -2
- package/dist/index.js +38 -25
- package/package.json +1 -1
package/dev-server-index.html
CHANGED
|
@@ -1,6 +1,186 @@
|
|
|
1
|
-
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Rails Vite</title>
|
|
7
|
+
<style>
|
|
8
|
+
*,
|
|
9
|
+
*::before,
|
|
10
|
+
*::after {
|
|
11
|
+
box-sizing: border-box;
|
|
12
|
+
margin: 0;
|
|
13
|
+
padding: 0;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
html {
|
|
17
|
+
-webkit-font-smoothing: antialiased;
|
|
18
|
+
-moz-osx-font-smoothing: grayscale;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
body {
|
|
22
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
|
|
23
|
+
Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji";
|
|
24
|
+
min-height: 100vh;
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
justify-content: center;
|
|
28
|
+
background-color: #f8f9fa;
|
|
29
|
+
color: #374151;
|
|
30
|
+
line-height: 1.6;
|
|
31
|
+
padding: 1.5rem;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
@media (prefers-color-scheme: dark) {
|
|
35
|
+
body {
|
|
36
|
+
background-color: #111827;
|
|
37
|
+
color: #9ca3af;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
.card {
|
|
42
|
+
background: #fff;
|
|
43
|
+
border-radius: 12px;
|
|
44
|
+
box-shadow:
|
|
45
|
+
0 1px 3px rgba(0, 0, 0, 0.06),
|
|
46
|
+
0 20px 40px rgba(0, 0, 0, 0.07);
|
|
47
|
+
max-width: 520px;
|
|
48
|
+
width: 100%;
|
|
49
|
+
padding: 2.5rem 2rem;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
@media (prefers-color-scheme: dark) {
|
|
53
|
+
.card {
|
|
54
|
+
background: #1f2937;
|
|
55
|
+
box-shadow:
|
|
56
|
+
0 1px 3px rgba(0, 0, 0, 0.2),
|
|
57
|
+
0 20px 40px rgba(0, 0, 0, 0.3);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.logos {
|
|
62
|
+
display: flex;
|
|
63
|
+
align-items: center;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
gap: 1.25rem;
|
|
66
|
+
margin-bottom: 2rem;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
.logos svg {
|
|
70
|
+
flex-shrink: 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
.plus {
|
|
74
|
+
color: #9ca3af;
|
|
75
|
+
font-size: 1.25rem;
|
|
76
|
+
font-weight: 300;
|
|
77
|
+
user-select: none;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.content p {
|
|
81
|
+
margin-bottom: 1rem;
|
|
82
|
+
font-size: 0.9375rem;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.content p:last-child {
|
|
86
|
+
margin-bottom: 0;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
.divider {
|
|
90
|
+
border: none;
|
|
91
|
+
border-top: 1px solid #e5e7eb;
|
|
92
|
+
margin: 1.5rem 0;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
@media (prefers-color-scheme: dark) {
|
|
96
|
+
.divider {
|
|
97
|
+
border-top-color: #374151;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.hint {
|
|
102
|
+
font-size: 0.8125rem;
|
|
103
|
+
color: #6b7280;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
@media (prefers-color-scheme: dark) {
|
|
107
|
+
.hint {
|
|
108
|
+
color: #6b7280;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
code {
|
|
113
|
+
font-family: ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas,
|
|
114
|
+
"Liberation Mono", monospace;
|
|
115
|
+
font-size: 0.8125rem;
|
|
116
|
+
background: #f3f4f6;
|
|
117
|
+
color: #1f2937;
|
|
118
|
+
padding: 0.15em 0.4em;
|
|
119
|
+
border-radius: 4px;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
@media (prefers-color-scheme: dark) {
|
|
123
|
+
code {
|
|
124
|
+
background: #374151;
|
|
125
|
+
color: #e5e7eb;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
a {
|
|
130
|
+
color: #cc342d;
|
|
131
|
+
text-decoration: none;
|
|
132
|
+
font-weight: 600;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
a:hover {
|
|
136
|
+
color: #a02a24;
|
|
137
|
+
text-decoration: underline;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
@media (prefers-color-scheme: dark) {
|
|
141
|
+
a {
|
|
142
|
+
color: #ef4444;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
a:hover {
|
|
146
|
+
color: #f87171;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
</style>
|
|
150
|
+
</head>
|
|
151
|
+
<body>
|
|
152
|
+
<div class="card">
|
|
153
|
+
<div class="logos">
|
|
154
|
+
<a href="https://rubyonrails.org" aria-label="Ruby on Rails">
|
|
155
|
+
<svg width="42" height="42" fill="#D30001" role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><title>Ruby on Rails</title><path d="M.741 19.365h8.36s-1.598-7.291 3.693-10.243l.134-.066c1.286-.637 4.907-2.431 10.702 1.854.19-.159.37-.286.37-.286s-5.503-5.492-11.63-4.878c-3.079.275-6.867 3.079-9.09 6.783C1.058 16.233.741 19.365.741 19.365Zm8.804-.783a10.682 10.682 0 0 1-.127-1.333l1.143.412c.063.498.159.963.254 1.376l-1.27-.455Zm-7.799-4.317L.529 13.82c-.201.455-.423.984-.529 1.27l1.217.444c.137-.359.36-.878.529-1.269Zm7.831.296.857.677c.042-.413.116-.825.222-1.238l-.762-.603c-.137.391-.233.783-.317 1.164Zm2.042-2.646-.508-.762c.191-.243.413-.486.656-.709l.476.72a5.958 5.958 0 0 0-.624.751ZM4.19 8.878l.752.656c-.254.265-.498.551-.72.836l-.815-.698c.244-.265.508-.529.783-.794Zm9.799 1.027-.243-.73c.265-.117.571-.233.931-.339l.233.698a6.82 6.82 0 0 0-.921.371Zm3.122-.656.042-.667c.339.021.688.064 1.048.138l-.042.656a5.859 5.859 0 0 0-1.048-.127ZM8.942 6.392l-.476-.731c-.265.138-.54.286-.826.455l.487.741c.275-.169.54-.328.815-.465Zm9.217-.053.042-.709c-.095-.053-.36-.18-1.026-.371l-.043.699c.349.116.688.243 1.027.381ZM13.238 5.28h.106l-.212-.645c-.328 0-.666.021-1.016.063l.201.625a8.87 8.87 0 0 1 .921-.043Z"/></svg>
|
|
156
|
+
</a>
|
|
157
|
+
<span class="plus">+</span>
|
|
158
|
+
<a href="https://vite.dev" aria-label="Vite">
|
|
159
|
+
<svg width="38" height="38" viewBox="0 0 410 404" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
160
|
+
<path d="M399.641 59.525 215.643 388.545c-3.816 6.826-13.638 6.994-17.69.304L7.876 59.221c-4.456-7.348 2.596-15.985 10.707-13.608l187.033 54.783c1.318.386 2.706.395 4.028.025L393.244 45.9c8.124-2.32 15.053 6.396 10.397 13.625Z" fill="url(#vite-a)"/>
|
|
161
|
+
<path d="M293.573 1.34 163.46 28.672c-2.2.462-3.834 2.347-3.967 4.577l-8.624 144.716c-.178 2.991 2.798 5.224 5.667 4.254l25.488-8.625c3.14-1.063 6.209 1.589 5.67 4.9l-7.828 48.08c-.555 3.412 2.72 6.085 5.882 4.8l19.6-7.952c3.16-1.282 6.433 1.39 5.878 4.8l-12.44 76.427c-.857 5.265 5.727 8.142 8.808 3.85l2.06-2.867L341.3 103.14c1.665-3.2-1.17-6.855-4.633-5.975l-26.357 6.698c-3.28.834-6.227-2.18-5.286-5.406L331.34 7.21c.95-3.25-2.065-6.296-5.3-5.358l-32.467 8.488Z" fill="url(#vite-b)"/>
|
|
162
|
+
<defs>
|
|
163
|
+
<linearGradient id="vite-a" x1="6.715" y1="32.086" x2="235.479" y2="344.885" gradientUnits="userSpaceOnUse">
|
|
164
|
+
<stop stop-color="#41D1FF"/>
|
|
165
|
+
<stop offset="1" stop-color="#BD34FE"/>
|
|
166
|
+
</linearGradient>
|
|
167
|
+
<linearGradient id="vite-b" x1="194.651" y1="8.818" x2="236.076" y2="292.989" gradientUnits="userSpaceOnUse">
|
|
168
|
+
<stop stop-color="#FFBD4F"/>
|
|
169
|
+
<stop offset="1" stop-color="#FF9640"/>
|
|
170
|
+
</linearGradient>
|
|
171
|
+
</defs>
|
|
172
|
+
</svg>
|
|
173
|
+
</a>
|
|
174
|
+
</div>
|
|
175
|
+
<div class="content">
|
|
176
|
+
<p>This is the <strong>Vite development server</strong> providing Hot Module Replacement for your Rails application.</p>
|
|
177
|
+
<p>Your Rails app is running on a different port. Start it with:</p>
|
|
178
|
+
<p><code>bin/dev</code></p>
|
|
179
|
+
<hr class="divider">
|
|
180
|
+
<p class="hint">
|
|
181
|
+
Need help? Read the <a href="https://github.com/skryukov/rails_vite#readme">docs →</a>
|
|
182
|
+
</p>
|
|
183
|
+
</div>
|
|
184
|
+
</div>
|
|
185
|
+
</body>
|
|
6
186
|
</html>
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Plugin } from 'vite';
|
|
2
|
+
export type InputOption = string | string[] | Record<string, string>;
|
|
2
3
|
export interface RailsViteOptions {
|
|
3
|
-
input?:
|
|
4
|
+
input?: InputOption;
|
|
4
5
|
sourceDir?: string;
|
|
5
|
-
ssr?:
|
|
6
|
+
ssr?: InputOption;
|
|
6
7
|
ssrOutputDirectory?: string;
|
|
7
8
|
devMetaFile?: string;
|
|
8
9
|
buildDirectory?: string;
|
|
9
10
|
publicDirectory?: string;
|
|
10
11
|
refresh?: boolean | string | string[];
|
|
11
12
|
}
|
|
13
|
+
export declare const refreshPaths: string[];
|
|
12
14
|
export default function rails(options?: RailsViteOptions): Plugin;
|
package/dist/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import path from 'path';
|
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
import picomatch from 'picomatch';
|
|
5
5
|
import { loadEnv, defaultAllowedOrigins, } from 'vite';
|
|
6
|
-
const
|
|
6
|
+
export const refreshPaths = [
|
|
7
7
|
'app/views/**/*.{erb,slim,haml}',
|
|
8
8
|
'app/helpers/**/*.rb',
|
|
9
9
|
];
|
|
@@ -16,9 +16,8 @@ export default function rails(options = {}) {
|
|
|
16
16
|
const devMetaPath = options.devMetaFile ?? path.join('tmp', 'rails-vite.json');
|
|
17
17
|
const ssrOutputDirectory = options.ssrOutputDirectory ?? 'ssr';
|
|
18
18
|
const resolvedInput = resolveInput(input, sourceDir);
|
|
19
|
-
const resolvedSsr = options.ssr ? resolveInput(options.ssr, sourceDir) : undefined;
|
|
19
|
+
const resolvedSsr = options.ssr !== undefined ? resolveInput(options.ssr, sourceDir) : undefined;
|
|
20
20
|
let resolvedConfig;
|
|
21
|
-
let devServerUrl;
|
|
22
21
|
let reactRefresh = false;
|
|
23
22
|
return {
|
|
24
23
|
name: 'rails-vite',
|
|
@@ -74,7 +73,7 @@ export default function rails(options = {}) {
|
|
|
74
73
|
server.httpServer?.once('listening', () => {
|
|
75
74
|
const address = server.httpServer?.address();
|
|
76
75
|
if (isAddressInfo(address)) {
|
|
77
|
-
devServerUrl = resolveDevServerUrl(address, resolvedConfig);
|
|
76
|
+
const devServerUrl = resolveDevServerUrl(address, resolvedConfig);
|
|
78
77
|
resolvedConfig.server.origin = devServerUrl;
|
|
79
78
|
const meta = { url: devServerUrl, sourceDir };
|
|
80
79
|
if (reactRefresh)
|
|
@@ -96,10 +95,10 @@ export default function rails(options = {}) {
|
|
|
96
95
|
exitHandlersBound = true;
|
|
97
96
|
}
|
|
98
97
|
// Watch view templates for full-page reload
|
|
99
|
-
const
|
|
100
|
-
if (
|
|
101
|
-
const match = picomatch(
|
|
102
|
-
server.watcher.add(
|
|
98
|
+
const resolvedRefreshPaths = resolveRefreshPaths(options.refresh);
|
|
99
|
+
if (resolvedRefreshPaths.length) {
|
|
100
|
+
const match = picomatch(resolvedRefreshPaths);
|
|
101
|
+
server.watcher.add(resolvedRefreshPaths);
|
|
103
102
|
server.watcher.on('change', (filePath) => {
|
|
104
103
|
const relativePath = path.relative(process.cwd(), filePath);
|
|
105
104
|
if (match(relativePath)) {
|
|
@@ -121,6 +120,9 @@ export default function rails(options = {}) {
|
|
|
121
120
|
};
|
|
122
121
|
}
|
|
123
122
|
function resolveInput(input, sourceDir) {
|
|
123
|
+
if (typeof input === 'object' && !Array.isArray(input)) {
|
|
124
|
+
return Object.fromEntries(Object.entries(input).map(([key, value]) => [key, prefixWithSourceDir(value, sourceDir)]));
|
|
125
|
+
}
|
|
124
126
|
if (Array.isArray(input)) {
|
|
125
127
|
return input.map((entry) => prefixWithSourceDir(entry, sourceDir));
|
|
126
128
|
}
|
|
@@ -132,9 +134,13 @@ function prefixWithSourceDir(entry, sourceDir) {
|
|
|
132
134
|
}
|
|
133
135
|
return `${sourceDir}/${entry}`;
|
|
134
136
|
}
|
|
135
|
-
const
|
|
137
|
+
const entrypointExtensions = /\.(mjs|js|mts|ts|jsx|tsx|css|scss|sass|less|styl|pcss)$/;
|
|
136
138
|
function detectEntrypoint(sourceDir) {
|
|
137
|
-
|
|
139
|
+
const entrypointsDir = path.join(sourceDir, 'entrypoints');
|
|
140
|
+
if (fs.existsSync(entrypointsDir)) {
|
|
141
|
+
return discoverEntrypoints(entrypointsDir).map((entry) => `entrypoints/${entry}`);
|
|
142
|
+
}
|
|
143
|
+
for (const ext of ['.js', '.mjs', '.ts', '.mts', '.jsx', '.tsx']) {
|
|
138
144
|
const candidate = path.join(sourceDir, `application${ext}`);
|
|
139
145
|
if (fs.existsSync(candidate)) {
|
|
140
146
|
return `application${ext}`;
|
|
@@ -142,35 +148,42 @@ function detectEntrypoint(sourceDir) {
|
|
|
142
148
|
}
|
|
143
149
|
return 'application.js';
|
|
144
150
|
}
|
|
145
|
-
function
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
+
function discoverEntrypoints(dir, base = dir) {
|
|
152
|
+
const entries = [];
|
|
153
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
154
|
+
if (entry.isDirectory()) {
|
|
155
|
+
entries.push(...discoverEntrypoints(path.join(dir, entry.name), base));
|
|
156
|
+
}
|
|
157
|
+
else if (entrypointExtensions.test(entry.name)) {
|
|
158
|
+
entries.push(path.relative(base, path.join(dir, entry.name)));
|
|
159
|
+
}
|
|
151
160
|
}
|
|
152
|
-
|
|
161
|
+
return entries;
|
|
162
|
+
}
|
|
163
|
+
function resolveRefreshPaths(refresh) {
|
|
164
|
+
if (refresh === false)
|
|
165
|
+
return [];
|
|
166
|
+
if (!refresh || refresh === true)
|
|
167
|
+
return refreshPaths;
|
|
168
|
+
if (typeof refresh === 'string')
|
|
153
169
|
return [refresh];
|
|
154
|
-
}
|
|
155
170
|
return refresh;
|
|
156
171
|
}
|
|
157
172
|
function resolveDevServerUrl(address, config) {
|
|
158
|
-
const
|
|
159
|
-
const clientProtocol =
|
|
160
|
-
?
|
|
173
|
+
const hmr = typeof config.server.hmr === 'object' ? config.server.hmr : null;
|
|
174
|
+
const clientProtocol = hmr?.protocol
|
|
175
|
+
? hmr.protocol === 'wss'
|
|
161
176
|
? 'https'
|
|
162
177
|
: 'http'
|
|
163
178
|
: null;
|
|
164
179
|
const serverProtocol = config.server.https ? 'https' : 'http';
|
|
165
180
|
const protocol = clientProtocol ?? serverProtocol;
|
|
166
|
-
const configHmrHost = typeof config.server.hmr === 'object' ? config.server.hmr.host : null;
|
|
167
181
|
const configHost = typeof config.server.host === 'string' ? config.server.host : null;
|
|
168
182
|
const serverAddress = address.family === 'IPv6' || address.family === 6
|
|
169
183
|
? `[${address.address}]`
|
|
170
184
|
: address.address;
|
|
171
|
-
const host =
|
|
172
|
-
const
|
|
173
|
-
const port = configHmrClientPort ?? address.port;
|
|
185
|
+
const host = hmr?.host ?? configHost ?? serverAddress;
|
|
186
|
+
const port = hmr?.clientPort ?? address.port;
|
|
174
187
|
return `${protocol}://${host}:${port}`;
|
|
175
188
|
}
|
|
176
189
|
function isAddressInfo(x) {
|