ruact 0.0.1 → 0.0.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2178853f396d86e745518fafefe519f54ee2d941aefa956d14dce639567e0dc3
4
- data.tar.gz: c48ae371e9ba39e90a4db67e6a815fc6e5b2a982d9fe87709b41b36e9b83ff6b
3
+ metadata.gz: afe1e13c5db7526aadaae7d270a47fcdb7b5dd07f129e06ea73949e23a1165ed
4
+ data.tar.gz: d25760765e47fe14f92c05c93979fc4cc03ec8a7e17e76d8006c04b44c86c0fd
5
5
  SHA512:
6
- metadata.gz: 3343bf04f0e4133aad881e65c97b1d701de33f00337a9eab1a98d9369d30dd2d355e7e566356505602a5041b575efc8547a142bc6ac997a8e36f753a919123bf
7
- data.tar.gz: 328442e7e003bed71f9757805ad2620f89f57a49a8f5823b38a5082c7886618054dcfd0276bc68b59568514b2f1d6a69217e4213b5a947514f5a6d7e767b9324
6
+ metadata.gz: 4d3bd528d4b006a20cbbe1c3331c6801643d501f234a6a0ec9bfd095fc1a9ded112bf1234350d964fab93b11f7f07172d3a34ba747911461d2a67316e238c9d1
7
+ data.tar.gz: 97d05fc03cdaa06de7de14a64864bb2a37885ab48a175f90f8b65e45d4144ceada5503a2182cff5d907b156131406e58eabdc5b166ba08464e20abac9916b578
data/lib/ruact/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Ruact
4
- VERSION = "0.0.1"
4
+ VERSION = "0.0.2"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruact
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luiz Garcia
@@ -31,7 +31,6 @@ extra_rdoc_files: []
31
31
  files:
32
32
  - ".github/workflows/ci.yml"
33
33
  - ".rubocop.yml"
34
- - "/Users/luiz/workspace/rails-rsc/gem/vendor/javascript/vite-plugin-ruact/index.js"
35
34
  - CHANGELOG.md
36
35
  - README.md
37
36
  - RELEASING.md
@@ -104,7 +103,6 @@ files:
104
103
  - spec/spec_helper.rb
105
104
  - spec/support/matchers/flight_fixture_matcher.rb
106
105
  - spec/support/rails_stub.rb
107
- - vendor/javascript/vite-plugin-ruact/index.js
108
106
  homepage: https://luizcg.github.io/ruact/
109
107
  licenses:
110
108
  - MIT
@@ -1,163 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
-
4
- /**
5
- * vite-plugin-ruact
6
- *
7
- * Scans app/javascript/components for files with "use client" directives and
8
- * emits public/react-client-manifest.json so the Rails gem can resolve
9
- * component names to chunk URLs.
10
- *
11
- * Manifest format:
12
- * {
13
- * "LikeButton": {
14
- * "id": "/assets/LikeButton-abc123.js",
15
- * "name": "LikeButton",
16
- * "chunks": ["/assets/LikeButton-abc123.js"]
17
- * }
18
- * }
19
- */
20
- export default function ruact(options = {}) {
21
- const {
22
- componentsDir = "app/javascript/components",
23
- manifestOutput = "public/react-client-manifest.json",
24
- } = options;
25
-
26
- let root;
27
- let manifest = {};
28
-
29
- return {
30
- name: "vite-plugin-ruact",
31
-
32
- configResolved(config) {
33
- root = config.root;
34
- },
35
-
36
- // During dev: build the manifest from source files
37
- buildStart() {
38
- manifest = buildManifest(path.resolve(root, componentsDir));
39
- writeManifest(path.resolve(root, manifestOutput), manifest);
40
- },
41
-
42
- // During build: update with hashed chunk URLs from the bundle
43
- generateBundle(_options, bundle) {
44
- const updated = {};
45
-
46
- for (const [chunkFileName, chunk] of Object.entries(bundle)) {
47
- if (chunk.type !== "chunk") continue;
48
-
49
- const facadeId = chunk.facadeModuleId;
50
- if (!facadeId) continue;
51
-
52
- // Find manifest entries whose source file matches this chunk
53
- for (const [name, entry] of Object.entries(manifest)) {
54
- if (facadeId === entry._sourceFile) {
55
- const url = "/" + chunkFileName;
56
- updated[name] = {
57
- id: url,
58
- name,
59
- chunks: [url],
60
- };
61
- }
62
- }
63
- }
64
-
65
- // Merge: keep entries that didn't get a hashed URL (dev mode)
66
- const final = { ...manifest, ...updated };
67
- // Strip internal _sourceFile field
68
- for (const entry of Object.values(final)) {
69
- delete entry._sourceFile;
70
- }
71
-
72
- writeManifest(path.resolve(root, manifestOutput), final);
73
- },
74
-
75
- // Dev server: watch components dir and rebuild manifest on change
76
- configureServer(server) {
77
- const dir = path.resolve(root, componentsDir);
78
- server.watcher.add(dir);
79
- server.watcher.on("change", (file) => {
80
- if (file.startsWith(dir)) {
81
- manifest = buildManifest(dir);
82
- writeManifest(path.resolve(root, manifestOutput), manifest);
83
- }
84
- });
85
- },
86
- };
87
- }
88
-
89
- function buildManifest(componentsDir) {
90
- const manifest = {};
91
-
92
- if (!fs.existsSync(componentsDir)) return manifest;
93
-
94
- const files = walkDir(componentsDir).filter((f) =>
95
- /\.(jsx?|tsx?)$/.test(f)
96
- );
97
-
98
- for (const file of files) {
99
- const content = fs.readFileSync(file, "utf8");
100
- if (!hasUseClient(content)) continue;
101
-
102
- const exports = extractExportNames(content);
103
- const relUrl = "/" + path.relative(componentsDir, file);
104
-
105
- for (const name of exports) {
106
- manifest[name] = {
107
- id: relUrl,
108
- name,
109
- chunks: [relUrl],
110
- _sourceFile: file, // used during build to match hashed chunks
111
- };
112
- }
113
- }
114
-
115
- return manifest;
116
- }
117
-
118
- function hasUseClient(content) {
119
- // "use client" must appear as a directive at the top of the file
120
- return /^\s*["']use client["']/m.test(content);
121
- }
122
-
123
- function extractExportNames(content) {
124
- const names = new Set();
125
-
126
- // export function Foo
127
- // export const Foo
128
- // export class Foo
129
- const namedRe = /export\s+(?:default\s+)?(?:function|const|class|let|var)\s+([A-Z][A-Za-z0-9]*)/g;
130
- let m;
131
- while ((m = namedRe.exec(content)) !== null) {
132
- names.add(m[1]);
133
- }
134
-
135
- // export { Foo, Bar }
136
- const bracedRe = /export\s+\{([^}]+)\}/g;
137
- while ((m = bracedRe.exec(content)) !== null) {
138
- for (const part of m[1].split(",")) {
139
- const name = part.trim().split(/\s+as\s+/).pop().trim();
140
- if (/^[A-Z]/.test(name)) names.add(name);
141
- }
142
- }
143
-
144
- return Array.from(names);
145
- }
146
-
147
- function writeManifest(outputPath, manifest) {
148
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
149
- fs.writeFileSync(outputPath, JSON.stringify(manifest, null, 2));
150
- }
151
-
152
- function walkDir(dir) {
153
- const results = [];
154
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
155
- const full = path.join(dir, entry.name);
156
- if (entry.isDirectory()) {
157
- results.push(...walkDir(full));
158
- } else {
159
- results.push(full);
160
- }
161
- }
162
- return results;
163
- }
@@ -1,163 +0,0 @@
1
- import fs from "node:fs";
2
- import path from "node:path";
3
-
4
- /**
5
- * vite-plugin-ruact
6
- *
7
- * Scans app/javascript/components for files with "use client" directives and
8
- * emits public/react-client-manifest.json so the Rails gem can resolve
9
- * component names to chunk URLs.
10
- *
11
- * Manifest format:
12
- * {
13
- * "LikeButton": {
14
- * "id": "/assets/LikeButton-abc123.js",
15
- * "name": "LikeButton",
16
- * "chunks": ["/assets/LikeButton-abc123.js"]
17
- * }
18
- * }
19
- */
20
- export default function ruact(options = {}) {
21
- const {
22
- componentsDir = "app/javascript/components",
23
- manifestOutput = "public/react-client-manifest.json",
24
- } = options;
25
-
26
- let root;
27
- let manifest = {};
28
-
29
- return {
30
- name: "vite-plugin-ruact",
31
-
32
- configResolved(config) {
33
- root = config.root;
34
- },
35
-
36
- // During dev: build the manifest from source files
37
- buildStart() {
38
- manifest = buildManifest(path.resolve(root, componentsDir));
39
- writeManifest(path.resolve(root, manifestOutput), manifest);
40
- },
41
-
42
- // During build: update with hashed chunk URLs from the bundle
43
- generateBundle(_options, bundle) {
44
- const updated = {};
45
-
46
- for (const [chunkFileName, chunk] of Object.entries(bundle)) {
47
- if (chunk.type !== "chunk") continue;
48
-
49
- const facadeId = chunk.facadeModuleId;
50
- if (!facadeId) continue;
51
-
52
- // Find manifest entries whose source file matches this chunk
53
- for (const [name, entry] of Object.entries(manifest)) {
54
- if (facadeId === entry._sourceFile) {
55
- const url = "/" + chunkFileName;
56
- updated[name] = {
57
- id: url,
58
- name,
59
- chunks: [url],
60
- };
61
- }
62
- }
63
- }
64
-
65
- // Merge: keep entries that didn't get a hashed URL (dev mode)
66
- const final = { ...manifest, ...updated };
67
- // Strip internal _sourceFile field
68
- for (const entry of Object.values(final)) {
69
- delete entry._sourceFile;
70
- }
71
-
72
- writeManifest(path.resolve(root, manifestOutput), final);
73
- },
74
-
75
- // Dev server: watch components dir and rebuild manifest on change
76
- configureServer(server) {
77
- const dir = path.resolve(root, componentsDir);
78
- server.watcher.add(dir);
79
- server.watcher.on("change", (file) => {
80
- if (file.startsWith(dir)) {
81
- manifest = buildManifest(dir);
82
- writeManifest(path.resolve(root, manifestOutput), manifest);
83
- }
84
- });
85
- },
86
- };
87
- }
88
-
89
- function buildManifest(componentsDir) {
90
- const manifest = {};
91
-
92
- if (!fs.existsSync(componentsDir)) return manifest;
93
-
94
- const files = walkDir(componentsDir).filter((f) =>
95
- /\.(jsx?|tsx?)$/.test(f)
96
- );
97
-
98
- for (const file of files) {
99
- const content = fs.readFileSync(file, "utf8");
100
- if (!hasUseClient(content)) continue;
101
-
102
- const exports = extractExportNames(content);
103
- const relUrl = "/" + path.relative(componentsDir, file);
104
-
105
- for (const name of exports) {
106
- manifest[name] = {
107
- id: relUrl,
108
- name,
109
- chunks: [relUrl],
110
- _sourceFile: file, // used during build to match hashed chunks
111
- };
112
- }
113
- }
114
-
115
- return manifest;
116
- }
117
-
118
- function hasUseClient(content) {
119
- // "use client" must appear as a directive at the top of the file
120
- return /^\s*["']use client["']/m.test(content);
121
- }
122
-
123
- function extractExportNames(content) {
124
- const names = new Set();
125
-
126
- // export function Foo
127
- // export const Foo
128
- // export class Foo
129
- const namedRe = /export\s+(?:default\s+)?(?:function|const|class|let|var)\s+([A-Z][A-Za-z0-9]*)/g;
130
- let m;
131
- while ((m = namedRe.exec(content)) !== null) {
132
- names.add(m[1]);
133
- }
134
-
135
- // export { Foo, Bar }
136
- const bracedRe = /export\s+\{([^}]+)\}/g;
137
- while ((m = bracedRe.exec(content)) !== null) {
138
- for (const part of m[1].split(",")) {
139
- const name = part.trim().split(/\s+as\s+/).pop().trim();
140
- if (/^[A-Z]/.test(name)) names.add(name);
141
- }
142
- }
143
-
144
- return Array.from(names);
145
- }
146
-
147
- function writeManifest(outputPath, manifest) {
148
- fs.mkdirSync(path.dirname(outputPath), { recursive: true });
149
- fs.writeFileSync(outputPath, JSON.stringify(manifest, null, 2));
150
- }
151
-
152
- function walkDir(dir) {
153
- const results = [];
154
- for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
155
- const full = path.join(dir, entry.name);
156
- if (entry.isDirectory()) {
157
- results.push(...walkDir(full));
158
- } else {
159
- results.push(full);
160
- }
161
- }
162
- return results;
163
- }