@fictjs/vite-plugin 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.
- package/README.md +17 -0
- package/dist/index.cjs +135 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +34 -0
- package/dist/index.d.ts +34 -0
- package/dist/index.js +114 -0
- package/dist/index.js.map +1 -0
- package/package.json +46 -0
package/README.md
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# @fictjs/vite-plugin
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+

|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
Vite plugin for Fict
|
|
8
|
+
|
|
9
|
+
## Usage
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install -D @fictjs/vite-plugin
|
|
13
|
+
# or
|
|
14
|
+
yarn add -D @fictjs/vite-plugin
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
You can visit [Fict](https://github.com/fictjs/fict) for more documentation.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// src/index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
default: () => fict
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
var import_core = require("@babel/core");
|
|
27
|
+
var import_compiler = require("@fictjs/compiler");
|
|
28
|
+
function fict(options = {}) {
|
|
29
|
+
const {
|
|
30
|
+
include = ["**/*.tsx", "**/*.jsx"],
|
|
31
|
+
exclude = ["**/node_modules/**"],
|
|
32
|
+
...compilerOptions
|
|
33
|
+
} = options;
|
|
34
|
+
let config;
|
|
35
|
+
let isDev = false;
|
|
36
|
+
return {
|
|
37
|
+
name: "vite-plugin-fict",
|
|
38
|
+
enforce: "pre",
|
|
39
|
+
configResolved(resolvedConfig) {
|
|
40
|
+
config = resolvedConfig;
|
|
41
|
+
isDev = config.command === "serve" || config.mode === "development";
|
|
42
|
+
},
|
|
43
|
+
config() {
|
|
44
|
+
return {
|
|
45
|
+
esbuild: {
|
|
46
|
+
// Disable esbuild JSX handling for .tsx/.jsx files
|
|
47
|
+
// Our plugin will handle the full transformation
|
|
48
|
+
include: /\.(ts|js|mts|mjs|cjs)$/
|
|
49
|
+
},
|
|
50
|
+
optimizeDeps: {
|
|
51
|
+
// Ensure @fictjs/runtime is pre-bundled
|
|
52
|
+
include: ["@fictjs/runtime"]
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
},
|
|
56
|
+
async transform(code, id) {
|
|
57
|
+
const filename = stripQuery(id);
|
|
58
|
+
if (!shouldTransform(filename, include, exclude)) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
try {
|
|
62
|
+
const fictOptions = {
|
|
63
|
+
...compilerOptions,
|
|
64
|
+
dev: compilerOptions.dev ?? isDev,
|
|
65
|
+
sourcemap: compilerOptions.sourcemap ?? true
|
|
66
|
+
};
|
|
67
|
+
const isTypeScript = filename.endsWith(".tsx") || filename.endsWith(".ts");
|
|
68
|
+
const result = await (0, import_core.transformAsync)(code, {
|
|
69
|
+
filename,
|
|
70
|
+
sourceMaps: fictOptions.sourcemap,
|
|
71
|
+
sourceFileName: filename,
|
|
72
|
+
presets: isTypeScript ? [["@babel/preset-typescript", { isTSX: true, allExtensions: true }]] : [],
|
|
73
|
+
plugins: [
|
|
74
|
+
["@babel/plugin-syntax-jsx", {}],
|
|
75
|
+
[import_compiler.createFictPlugin, fictOptions]
|
|
76
|
+
]
|
|
77
|
+
});
|
|
78
|
+
if (!result || !result.code) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
code: result.code,
|
|
83
|
+
map: result.map
|
|
84
|
+
};
|
|
85
|
+
} catch (error) {
|
|
86
|
+
const message = error instanceof Error ? error.message : "Unknown error during Fict transformation";
|
|
87
|
+
this.error({
|
|
88
|
+
message: `[fict] Transform failed for ${id}: ${message}`,
|
|
89
|
+
id
|
|
90
|
+
});
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
},
|
|
94
|
+
handleHotUpdate({ file, server }) {
|
|
95
|
+
if (shouldTransform(file, include, exclude)) {
|
|
96
|
+
server.ws.send({
|
|
97
|
+
type: "full-reload",
|
|
98
|
+
path: "*"
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
function shouldTransform(id, include, exclude) {
|
|
105
|
+
const normalizedId = stripQuery(id).replace(/\\/g, "/");
|
|
106
|
+
for (const pattern of exclude) {
|
|
107
|
+
if (matchPattern(normalizedId, pattern)) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
for (const pattern of include) {
|
|
112
|
+
if (matchPattern(normalizedId, pattern)) {
|
|
113
|
+
return true;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
function matchPattern(id, pattern) {
|
|
119
|
+
if (id === pattern) return true;
|
|
120
|
+
if (pattern.startsWith("**/") || pattern.startsWith("*")) {
|
|
121
|
+
const ext = pattern.replace(/^\*\*?\//, "");
|
|
122
|
+
if (ext.startsWith("*")) {
|
|
123
|
+
const ending = ext.replace(/^\*/, "");
|
|
124
|
+
return id.endsWith(ending);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
|
|
128
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
129
|
+
return regex.test(id);
|
|
130
|
+
}
|
|
131
|
+
function stripQuery(id) {
|
|
132
|
+
const queryStart = id.indexOf("?");
|
|
133
|
+
return queryStart === -1 ? id : id.slice(0, queryStart);
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { transformAsync } from '@babel/core'\nimport { createFictPlugin, type FictCompilerOptions } from '@fictjs/compiler'\nimport type { Plugin, TransformResult, ResolvedConfig } from 'vite'\n\nexport interface FictPluginOptions extends FictCompilerOptions {\n /**\n * File patterns to include for transformation.\n * @default ['**\\/*.tsx', '**\\/*.jsx']\n */\n include?: string[]\n /**\n * File patterns to exclude from transformation.\n * @default ['**\\/node_modules\\/**']\n */\n exclude?: string[]\n}\n\n/**\n * Vite plugin for Fict reactive UI library.\n *\n * Transforms $state and $effect calls into reactive signals using the Fict compiler.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite'\n * import fict from '@fictjs/vite-plugin'\n *\n * export default defineConfig({\n * plugins: [fict()],\n * })\n * ```\n */\nexport default function fict(options: FictPluginOptions = {}): Plugin {\n const {\n include = ['**/*.tsx', '**/*.jsx'],\n exclude = ['**/node_modules/**'],\n ...compilerOptions\n } = options\n\n let config: ResolvedConfig\n let isDev = false\n\n return {\n name: 'vite-plugin-fict',\n\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig\n isDev = config.command === 'serve' || config.mode === 'development'\n },\n\n config() {\n return {\n esbuild: {\n // Disable esbuild JSX handling for .tsx/.jsx files\n // Our plugin will handle the full transformation\n include: /\\.(ts|js|mts|mjs|cjs)$/,\n },\n optimizeDeps: {\n // Ensure @fictjs/runtime is pre-bundled\n include: ['@fictjs/runtime'],\n },\n }\n },\n\n async transform(code: string, id: string): Promise<TransformResult | null> {\n const filename = stripQuery(id)\n\n // Skip non-matching files\n if (!shouldTransform(filename, include, exclude)) {\n return null\n }\n\n try {\n // Pass dev mode to compiler for debug instrumentation\n const fictOptions: FictCompilerOptions = {\n ...compilerOptions,\n dev: compilerOptions.dev ?? isDev,\n sourcemap: compilerOptions.sourcemap ?? true,\n }\n\n const isTypeScript = filename.endsWith('.tsx') || filename.endsWith('.ts')\n\n const result = await transformAsync(code, {\n filename,\n sourceMaps: fictOptions.sourcemap,\n sourceFileName: filename,\n presets: isTypeScript\n ? [['@babel/preset-typescript', { isTSX: true, allExtensions: true }]]\n : [],\n plugins: [\n ['@babel/plugin-syntax-jsx', {}],\n [createFictPlugin, fictOptions],\n ],\n })\n\n if (!result || !result.code) {\n return null\n }\n\n return {\n code: result.code,\n map: result.map as TransformResult['map'],\n }\n } catch (error) {\n // Better error handling\n const message =\n error instanceof Error ? error.message : 'Unknown error during Fict transformation'\n\n this.error({\n message: `[fict] Transform failed for ${id}: ${message}`,\n id,\n })\n\n return null\n }\n },\n\n handleHotUpdate({ file, server }) {\n // Force full reload for .tsx/.jsx files to ensure reactive graph is rebuilt\n if (shouldTransform(file, include, exclude)) {\n server.ws.send({\n type: 'full-reload',\n path: '*',\n })\n }\n },\n }\n}\n\n/**\n * Check if a file should be transformed based on include/exclude patterns\n */\nfunction shouldTransform(id: string, include: string[], exclude: string[]): boolean {\n // Normalize path separators\n const normalizedId = stripQuery(id).replace(/\\\\/g, '/')\n\n // Check exclude patterns first\n for (const pattern of exclude) {\n if (matchPattern(normalizedId, pattern)) {\n return false\n }\n }\n\n // Check include patterns\n for (const pattern of include) {\n if (matchPattern(normalizedId, pattern)) {\n return true\n }\n }\n\n return false\n}\n\n/**\n * Simple glob pattern matching\n * Supports: **\\/*.ext, *.ext, exact matches\n */\nfunction matchPattern(id: string, pattern: string): boolean {\n // Exact match\n if (id === pattern) return true\n\n // Simple check: if pattern ends with extension like *.tsx, just check if file ends with it\n if (pattern.startsWith('**/') || pattern.startsWith('*')) {\n const ext = pattern.replace(/^\\*\\*?\\//, '')\n if (ext.startsWith('*')) {\n // **/*.tsx -> check if ends with .tsx\n const ending = ext.replace(/^\\*/, '')\n return id.endsWith(ending)\n }\n }\n\n // Convert glob pattern to regex\n const regexPattern = pattern\n .replace(/\\./g, '\\\\.') // Escape dots\n .replace(/\\*\\*/g, '.*') // ** matches any path\n .replace(/\\*/g, '[^/]*') // * matches any non-slash\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(id)\n}\n\n/**\n * Remove Vite query parameters (e.g. ?import, ?v=123) from an id\n */\nfunction stripQuery(id: string): string {\n const queryStart = id.indexOf('?')\n return queryStart === -1 ? id : id.slice(0, queryStart)\n}\n"],"mappings":"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","names":[]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { FictCompilerOptions } from '@fictjs/compiler';
|
|
2
|
+
import { Plugin } from 'vite';
|
|
3
|
+
|
|
4
|
+
interface FictPluginOptions extends FictCompilerOptions {
|
|
5
|
+
/**
|
|
6
|
+
* File patterns to include for transformation.
|
|
7
|
+
* @default ['**\/*.tsx', '**\/*.jsx']
|
|
8
|
+
*/
|
|
9
|
+
include?: string[];
|
|
10
|
+
/**
|
|
11
|
+
* File patterns to exclude from transformation.
|
|
12
|
+
* @default ['**\/node_modules\/**']
|
|
13
|
+
*/
|
|
14
|
+
exclude?: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Vite plugin for Fict reactive UI library.
|
|
18
|
+
*
|
|
19
|
+
* Transforms $state and $effect calls into reactive signals using the Fict compiler.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* // vite.config.ts
|
|
24
|
+
* import { defineConfig } from 'vite'
|
|
25
|
+
* import fict from '@fictjs/vite-plugin'
|
|
26
|
+
*
|
|
27
|
+
* export default defineConfig({
|
|
28
|
+
* plugins: [fict()],
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare function fict(options?: FictPluginOptions): Plugin;
|
|
33
|
+
|
|
34
|
+
export { type FictPluginOptions, fict as default };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { FictCompilerOptions } from '@fictjs/compiler';
|
|
2
|
+
import { Plugin } from 'vite';
|
|
3
|
+
|
|
4
|
+
interface FictPluginOptions extends FictCompilerOptions {
|
|
5
|
+
/**
|
|
6
|
+
* File patterns to include for transformation.
|
|
7
|
+
* @default ['**\/*.tsx', '**\/*.jsx']
|
|
8
|
+
*/
|
|
9
|
+
include?: string[];
|
|
10
|
+
/**
|
|
11
|
+
* File patterns to exclude from transformation.
|
|
12
|
+
* @default ['**\/node_modules\/**']
|
|
13
|
+
*/
|
|
14
|
+
exclude?: string[];
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Vite plugin for Fict reactive UI library.
|
|
18
|
+
*
|
|
19
|
+
* Transforms $state and $effect calls into reactive signals using the Fict compiler.
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* // vite.config.ts
|
|
24
|
+
* import { defineConfig } from 'vite'
|
|
25
|
+
* import fict from '@fictjs/vite-plugin'
|
|
26
|
+
*
|
|
27
|
+
* export default defineConfig({
|
|
28
|
+
* plugins: [fict()],
|
|
29
|
+
* })
|
|
30
|
+
* ```
|
|
31
|
+
*/
|
|
32
|
+
declare function fict(options?: FictPluginOptions): Plugin;
|
|
33
|
+
|
|
34
|
+
export { type FictPluginOptions, fict as default };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { transformAsync } from "@babel/core";
|
|
3
|
+
import { createFictPlugin } from "@fictjs/compiler";
|
|
4
|
+
function fict(options = {}) {
|
|
5
|
+
const {
|
|
6
|
+
include = ["**/*.tsx", "**/*.jsx"],
|
|
7
|
+
exclude = ["**/node_modules/**"],
|
|
8
|
+
...compilerOptions
|
|
9
|
+
} = options;
|
|
10
|
+
let config;
|
|
11
|
+
let isDev = false;
|
|
12
|
+
return {
|
|
13
|
+
name: "vite-plugin-fict",
|
|
14
|
+
enforce: "pre",
|
|
15
|
+
configResolved(resolvedConfig) {
|
|
16
|
+
config = resolvedConfig;
|
|
17
|
+
isDev = config.command === "serve" || config.mode === "development";
|
|
18
|
+
},
|
|
19
|
+
config() {
|
|
20
|
+
return {
|
|
21
|
+
esbuild: {
|
|
22
|
+
// Disable esbuild JSX handling for .tsx/.jsx files
|
|
23
|
+
// Our plugin will handle the full transformation
|
|
24
|
+
include: /\.(ts|js|mts|mjs|cjs)$/
|
|
25
|
+
},
|
|
26
|
+
optimizeDeps: {
|
|
27
|
+
// Ensure @fictjs/runtime is pre-bundled
|
|
28
|
+
include: ["@fictjs/runtime"]
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
},
|
|
32
|
+
async transform(code, id) {
|
|
33
|
+
const filename = stripQuery(id);
|
|
34
|
+
if (!shouldTransform(filename, include, exclude)) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
try {
|
|
38
|
+
const fictOptions = {
|
|
39
|
+
...compilerOptions,
|
|
40
|
+
dev: compilerOptions.dev ?? isDev,
|
|
41
|
+
sourcemap: compilerOptions.sourcemap ?? true
|
|
42
|
+
};
|
|
43
|
+
const isTypeScript = filename.endsWith(".tsx") || filename.endsWith(".ts");
|
|
44
|
+
const result = await transformAsync(code, {
|
|
45
|
+
filename,
|
|
46
|
+
sourceMaps: fictOptions.sourcemap,
|
|
47
|
+
sourceFileName: filename,
|
|
48
|
+
presets: isTypeScript ? [["@babel/preset-typescript", { isTSX: true, allExtensions: true }]] : [],
|
|
49
|
+
plugins: [
|
|
50
|
+
["@babel/plugin-syntax-jsx", {}],
|
|
51
|
+
[createFictPlugin, fictOptions]
|
|
52
|
+
]
|
|
53
|
+
});
|
|
54
|
+
if (!result || !result.code) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
code: result.code,
|
|
59
|
+
map: result.map
|
|
60
|
+
};
|
|
61
|
+
} catch (error) {
|
|
62
|
+
const message = error instanceof Error ? error.message : "Unknown error during Fict transformation";
|
|
63
|
+
this.error({
|
|
64
|
+
message: `[fict] Transform failed for ${id}: ${message}`,
|
|
65
|
+
id
|
|
66
|
+
});
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
},
|
|
70
|
+
handleHotUpdate({ file, server }) {
|
|
71
|
+
if (shouldTransform(file, include, exclude)) {
|
|
72
|
+
server.ws.send({
|
|
73
|
+
type: "full-reload",
|
|
74
|
+
path: "*"
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
function shouldTransform(id, include, exclude) {
|
|
81
|
+
const normalizedId = stripQuery(id).replace(/\\/g, "/");
|
|
82
|
+
for (const pattern of exclude) {
|
|
83
|
+
if (matchPattern(normalizedId, pattern)) {
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
for (const pattern of include) {
|
|
88
|
+
if (matchPattern(normalizedId, pattern)) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
function matchPattern(id, pattern) {
|
|
95
|
+
if (id === pattern) return true;
|
|
96
|
+
if (pattern.startsWith("**/") || pattern.startsWith("*")) {
|
|
97
|
+
const ext = pattern.replace(/^\*\*?\//, "");
|
|
98
|
+
if (ext.startsWith("*")) {
|
|
99
|
+
const ending = ext.replace(/^\*/, "");
|
|
100
|
+
return id.endsWith(ending);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
const regexPattern = pattern.replace(/\./g, "\\.").replace(/\*\*/g, ".*").replace(/\*/g, "[^/]*");
|
|
104
|
+
const regex = new RegExp(`^${regexPattern}$`);
|
|
105
|
+
return regex.test(id);
|
|
106
|
+
}
|
|
107
|
+
function stripQuery(id) {
|
|
108
|
+
const queryStart = id.indexOf("?");
|
|
109
|
+
return queryStart === -1 ? id : id.slice(0, queryStart);
|
|
110
|
+
}
|
|
111
|
+
export {
|
|
112
|
+
fict as default
|
|
113
|
+
};
|
|
114
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["import { transformAsync } from '@babel/core'\nimport { createFictPlugin, type FictCompilerOptions } from '@fictjs/compiler'\nimport type { Plugin, TransformResult, ResolvedConfig } from 'vite'\n\nexport interface FictPluginOptions extends FictCompilerOptions {\n /**\n * File patterns to include for transformation.\n * @default ['**\\/*.tsx', '**\\/*.jsx']\n */\n include?: string[]\n /**\n * File patterns to exclude from transformation.\n * @default ['**\\/node_modules\\/**']\n */\n exclude?: string[]\n}\n\n/**\n * Vite plugin for Fict reactive UI library.\n *\n * Transforms $state and $effect calls into reactive signals using the Fict compiler.\n *\n * @example\n * ```ts\n * // vite.config.ts\n * import { defineConfig } from 'vite'\n * import fict from '@fictjs/vite-plugin'\n *\n * export default defineConfig({\n * plugins: [fict()],\n * })\n * ```\n */\nexport default function fict(options: FictPluginOptions = {}): Plugin {\n const {\n include = ['**/*.tsx', '**/*.jsx'],\n exclude = ['**/node_modules/**'],\n ...compilerOptions\n } = options\n\n let config: ResolvedConfig\n let isDev = false\n\n return {\n name: 'vite-plugin-fict',\n\n enforce: 'pre',\n\n configResolved(resolvedConfig) {\n config = resolvedConfig\n isDev = config.command === 'serve' || config.mode === 'development'\n },\n\n config() {\n return {\n esbuild: {\n // Disable esbuild JSX handling for .tsx/.jsx files\n // Our plugin will handle the full transformation\n include: /\\.(ts|js|mts|mjs|cjs)$/,\n },\n optimizeDeps: {\n // Ensure @fictjs/runtime is pre-bundled\n include: ['@fictjs/runtime'],\n },\n }\n },\n\n async transform(code: string, id: string): Promise<TransformResult | null> {\n const filename = stripQuery(id)\n\n // Skip non-matching files\n if (!shouldTransform(filename, include, exclude)) {\n return null\n }\n\n try {\n // Pass dev mode to compiler for debug instrumentation\n const fictOptions: FictCompilerOptions = {\n ...compilerOptions,\n dev: compilerOptions.dev ?? isDev,\n sourcemap: compilerOptions.sourcemap ?? true,\n }\n\n const isTypeScript = filename.endsWith('.tsx') || filename.endsWith('.ts')\n\n const result = await transformAsync(code, {\n filename,\n sourceMaps: fictOptions.sourcemap,\n sourceFileName: filename,\n presets: isTypeScript\n ? [['@babel/preset-typescript', { isTSX: true, allExtensions: true }]]\n : [],\n plugins: [\n ['@babel/plugin-syntax-jsx', {}],\n [createFictPlugin, fictOptions],\n ],\n })\n\n if (!result || !result.code) {\n return null\n }\n\n return {\n code: result.code,\n map: result.map as TransformResult['map'],\n }\n } catch (error) {\n // Better error handling\n const message =\n error instanceof Error ? error.message : 'Unknown error during Fict transformation'\n\n this.error({\n message: `[fict] Transform failed for ${id}: ${message}`,\n id,\n })\n\n return null\n }\n },\n\n handleHotUpdate({ file, server }) {\n // Force full reload for .tsx/.jsx files to ensure reactive graph is rebuilt\n if (shouldTransform(file, include, exclude)) {\n server.ws.send({\n type: 'full-reload',\n path: '*',\n })\n }\n },\n }\n}\n\n/**\n * Check if a file should be transformed based on include/exclude patterns\n */\nfunction shouldTransform(id: string, include: string[], exclude: string[]): boolean {\n // Normalize path separators\n const normalizedId = stripQuery(id).replace(/\\\\/g, '/')\n\n // Check exclude patterns first\n for (const pattern of exclude) {\n if (matchPattern(normalizedId, pattern)) {\n return false\n }\n }\n\n // Check include patterns\n for (const pattern of include) {\n if (matchPattern(normalizedId, pattern)) {\n return true\n }\n }\n\n return false\n}\n\n/**\n * Simple glob pattern matching\n * Supports: **\\/*.ext, *.ext, exact matches\n */\nfunction matchPattern(id: string, pattern: string): boolean {\n // Exact match\n if (id === pattern) return true\n\n // Simple check: if pattern ends with extension like *.tsx, just check if file ends with it\n if (pattern.startsWith('**/') || pattern.startsWith('*')) {\n const ext = pattern.replace(/^\\*\\*?\\//, '')\n if (ext.startsWith('*')) {\n // **/*.tsx -> check if ends with .tsx\n const ending = ext.replace(/^\\*/, '')\n return id.endsWith(ending)\n }\n }\n\n // Convert glob pattern to regex\n const regexPattern = pattern\n .replace(/\\./g, '\\\\.') // Escape dots\n .replace(/\\*\\*/g, '.*') // ** matches any path\n .replace(/\\*/g, '[^/]*') // * matches any non-slash\n\n const regex = new RegExp(`^${regexPattern}$`)\n return regex.test(id)\n}\n\n/**\n * Remove Vite query parameters (e.g. ?import, ?v=123) from an id\n */\nfunction stripQuery(id: string): string {\n const queryStart = id.indexOf('?')\n return queryStart === -1 ? id : id.slice(0, queryStart)\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@fictjs/vite-plugin",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Vite plugin for Fict",
|
|
5
|
+
"publishConfig": {
|
|
6
|
+
"access": "public"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"main": "dist/index.cjs",
|
|
10
|
+
"module": "dist/index.js",
|
|
11
|
+
"types": "dist/index.d.ts",
|
|
12
|
+
"exports": {
|
|
13
|
+
".": {
|
|
14
|
+
"types": "./dist/index.d.ts",
|
|
15
|
+
"import": "./dist/index.js",
|
|
16
|
+
"require": "./dist/index.cjs"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"dist"
|
|
21
|
+
],
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsup src/index.ts --format cjs,esm --dts",
|
|
24
|
+
"dev": "tsup src/index.ts --format cjs,esm --dts --watch",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"test:coverage": "vitest run --coverage",
|
|
27
|
+
"lint": "eslint src",
|
|
28
|
+
"typecheck": "tsc --noEmit",
|
|
29
|
+
"clean": "rm -rf dist"
|
|
30
|
+
},
|
|
31
|
+
"peerDependencies": {
|
|
32
|
+
"vite": ">=7.0.0"
|
|
33
|
+
},
|
|
34
|
+
"dependencies": {
|
|
35
|
+
"@babel/core": "^7.26.0",
|
|
36
|
+
"@babel/plugin-syntax-jsx": "^7.27.1",
|
|
37
|
+
"@babel/plugin-transform-react-jsx": "^7.25.9",
|
|
38
|
+
"@babel/preset-typescript": "^7.26.0",
|
|
39
|
+
"@fictjs/compiler": "workspace:*"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/babel__core": "^7.20.5",
|
|
43
|
+
"tsup": "^8.5.1",
|
|
44
|
+
"vite": "^7.2.7"
|
|
45
|
+
}
|
|
46
|
+
}
|