vite-file-include 1.0.0 → 1.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 +19 -10
- package/package.json +1 -1
- package/src/index.js +50 -31
package/README.md
CHANGED
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
# vite-
|
|
1
|
+
# vite-file-include
|
|
2
2
|
|
|
3
|
-
`vite-
|
|
3
|
+
`vite-file-include` is an advanced Vite plugin designed to facilitate the inclusion of external HTML files, looping through data, and conditional rendering within your HTML files. It is particularly useful for managing repetitive HTML structures in static sites or templating environments.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
7
|
- File inclusion with support for nested includes
|
|
8
8
|
- Looping through data arrays or JSON files
|
|
9
|
-
- Conditional rendering
|
|
10
|
-
- Caching mechanism for improved performance
|
|
9
|
+
- Conditional rendering
|
|
11
10
|
- Custom function support for advanced templating
|
|
11
|
+
- Evaluate JavaScript expressions directly in your templates.
|
|
12
12
|
- Asynchronous file processing
|
|
13
13
|
- Enhanced error handling and debugging
|
|
14
14
|
|
|
15
|
+
|
|
15
16
|
## Installation
|
|
16
17
|
|
|
17
18
|
Install the plugin via npm:
|
|
18
19
|
|
|
19
20
|
```bash
|
|
20
|
-
npm install vite-
|
|
21
|
+
npm install vite-file-include
|
|
21
22
|
```
|
|
22
23
|
|
|
23
24
|
## Configuration
|
|
@@ -25,7 +26,7 @@ npm install vite-plugin-file-include
|
|
|
25
26
|
To use the plugin, import and configure it in your `vite.config.js`:
|
|
26
27
|
|
|
27
28
|
```javascript
|
|
28
|
-
import fileIncludePlugin from 'vite-
|
|
29
|
+
import fileIncludePlugin from 'vite-file-include';
|
|
29
30
|
|
|
30
31
|
export default {
|
|
31
32
|
plugins: [
|
|
@@ -34,9 +35,8 @@ export default {
|
|
|
34
35
|
loopPattern: "@@loop",
|
|
35
36
|
ifPattern: "@@if",
|
|
36
37
|
baseDir: process.cwd(),
|
|
37
|
-
context: {},
|
|
38
|
+
context: {},
|
|
38
39
|
customFunctions: {},
|
|
39
|
-
cacheTimeout: 5000
|
|
40
40
|
}),
|
|
41
41
|
],
|
|
42
42
|
};
|
|
@@ -49,8 +49,7 @@ export default {
|
|
|
49
49
|
- `ifPattern` (default: `@@if`): The pattern used to conditionally render content.
|
|
50
50
|
- `baseDir` (default: `process.cwd()`): The base directory for resolving paths.
|
|
51
51
|
- `context` (default: `{}`): An object containing global variables that can be used in includes, loops, and conditionals.
|
|
52
|
-
- `customFunctions` (default:
|
|
53
|
-
- `cacheTimeout` (default: `5000`): The time (in milliseconds) after which cached content is invalidated.
|
|
52
|
+
- `customFunctions` (default: {}): An object containing custom functions that can be used in your templates.
|
|
54
53
|
|
|
55
54
|
## Directives
|
|
56
55
|
|
|
@@ -140,6 +139,16 @@ You can then use these functions in your templates:
|
|
|
140
139
|
<footer>© {{ currentYear() }}</footer>
|
|
141
140
|
```
|
|
142
141
|
|
|
142
|
+
|
|
143
|
+
## JavaScript Expressions
|
|
144
|
+
|
|
145
|
+
You can use JavaScript expressions directly in your templates. For example:
|
|
146
|
+
|
|
147
|
+
```html
|
|
148
|
+
<p>Current Year: {{ new Date().getFullYear() }}</p>
|
|
149
|
+
<p>Uppercase Text: {{ 'John'.toUpperCase() }}</p>
|
|
150
|
+
```
|
|
151
|
+
|
|
143
152
|
## Example Usage
|
|
144
153
|
|
|
145
154
|
Below is an example of how you might structure your HTML files using the plugin's directives:
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
|
|
4
|
-
function
|
|
4
|
+
function fileIncludePlugin(options = {}) {
|
|
5
5
|
const {
|
|
6
6
|
includePattern = "@@include",
|
|
7
7
|
loopPattern = "@@loop",
|
|
8
8
|
ifPattern = "@@if",
|
|
9
9
|
baseDir = process.cwd(),
|
|
10
10
|
context = {},
|
|
11
|
+
customFunctions = {},
|
|
11
12
|
} = options;
|
|
12
13
|
|
|
13
14
|
return {
|
|
@@ -20,7 +21,8 @@ function fileInclude(options = {}) {
|
|
|
20
21
|
includePattern,
|
|
21
22
|
loopPattern,
|
|
22
23
|
ifPattern,
|
|
23
|
-
context
|
|
24
|
+
context,
|
|
25
|
+
customFunctions
|
|
24
26
|
);
|
|
25
27
|
},
|
|
26
28
|
|
|
@@ -32,7 +34,8 @@ function fileInclude(options = {}) {
|
|
|
32
34
|
includePattern,
|
|
33
35
|
loopPattern,
|
|
34
36
|
ifPattern,
|
|
35
|
-
context
|
|
37
|
+
context,
|
|
38
|
+
customFunctions
|
|
36
39
|
);
|
|
37
40
|
}
|
|
38
41
|
return code;
|
|
@@ -54,7 +57,8 @@ function processIncludes(
|
|
|
54
57
|
includePattern,
|
|
55
58
|
loopPattern,
|
|
56
59
|
ifPattern,
|
|
57
|
-
context
|
|
60
|
+
context,
|
|
61
|
+
customFunctions
|
|
58
62
|
) {
|
|
59
63
|
content = processIncludesWithPattern(
|
|
60
64
|
content,
|
|
@@ -62,16 +66,18 @@ function processIncludes(
|
|
|
62
66
|
includePattern,
|
|
63
67
|
loopPattern,
|
|
64
68
|
ifPattern,
|
|
65
|
-
context
|
|
69
|
+
context,
|
|
70
|
+
customFunctions
|
|
66
71
|
);
|
|
67
|
-
content = processLoops(content, dir, loopPattern, context);
|
|
72
|
+
content = processLoops(content, dir, loopPattern, context, customFunctions);
|
|
68
73
|
content = processConditionals(
|
|
69
74
|
content,
|
|
70
75
|
dir,
|
|
71
76
|
ifPattern,
|
|
72
77
|
includePattern,
|
|
73
78
|
loopPattern,
|
|
74
|
-
context
|
|
79
|
+
context,
|
|
80
|
+
customFunctions
|
|
75
81
|
);
|
|
76
82
|
|
|
77
83
|
return content;
|
|
@@ -83,7 +89,8 @@ function processIncludesWithPattern(
|
|
|
83
89
|
includePattern,
|
|
84
90
|
loopPattern,
|
|
85
91
|
ifPattern,
|
|
86
|
-
context
|
|
92
|
+
context,
|
|
93
|
+
customFunctions
|
|
87
94
|
) {
|
|
88
95
|
const regex = new RegExp(
|
|
89
96
|
`${includePattern}\\(\\s*['"](.+?)['"]\\s*,?\\s*({[\\s\\S]*?})?\\s*\\);`,
|
|
@@ -104,14 +111,19 @@ function processIncludesWithPattern(
|
|
|
104
111
|
|
|
105
112
|
try {
|
|
106
113
|
let includedContent = fs.readFileSync(includePath, "utf-8");
|
|
107
|
-
includedContent = injectData(
|
|
114
|
+
includedContent = injectData(
|
|
115
|
+
includedContent,
|
|
116
|
+
{ ...context, ...data },
|
|
117
|
+
customFunctions
|
|
118
|
+
);
|
|
108
119
|
return processIncludes(
|
|
109
120
|
includedContent,
|
|
110
121
|
path.dirname(includePath),
|
|
111
122
|
includePattern,
|
|
112
123
|
loopPattern,
|
|
113
124
|
ifPattern,
|
|
114
|
-
context
|
|
125
|
+
context,
|
|
126
|
+
customFunctions
|
|
115
127
|
);
|
|
116
128
|
} catch (error) {
|
|
117
129
|
console.error(`Failed to include file: ${includePath}`);
|
|
@@ -120,7 +132,7 @@ function processIncludesWithPattern(
|
|
|
120
132
|
});
|
|
121
133
|
}
|
|
122
134
|
|
|
123
|
-
function processLoops(content, dir, loopPattern, context) {
|
|
135
|
+
function processLoops(content, dir, loopPattern, context, customFunctions) {
|
|
124
136
|
const regex = new RegExp(
|
|
125
137
|
`${loopPattern}\\(\\s*['"](.+?)['"]\\s*,\\s*(\\[[\\s\\S]*?\\]|['"](.+?)['"])\\s*\\);`,
|
|
126
138
|
"g"
|
|
@@ -131,15 +143,12 @@ function processLoops(content, dir, loopPattern, context) {
|
|
|
131
143
|
let dataArray = [];
|
|
132
144
|
|
|
133
145
|
try {
|
|
134
|
-
// Detect if the second argument is a JSON file path or a JSON array
|
|
135
146
|
if (
|
|
136
147
|
jsonArrayOrFilePath.startsWith("[") ||
|
|
137
148
|
jsonArrayOrFilePath.startsWith("{")
|
|
138
149
|
) {
|
|
139
|
-
// Handle JSON array or object directly provided in the directive
|
|
140
150
|
dataArray = JSON.parse(jsonArrayOrFilePath);
|
|
141
151
|
} else {
|
|
142
|
-
// Handle JSON file path
|
|
143
152
|
const jsonFilePath = path.resolve(
|
|
144
153
|
dir,
|
|
145
154
|
jsonArrayOrFilePath.replace(/['"]/g, "")
|
|
@@ -154,7 +163,9 @@ function processLoops(content, dir, loopPattern, context) {
|
|
|
154
163
|
|
|
155
164
|
try {
|
|
156
165
|
let loopTemplate = fs.readFileSync(loopPath, "utf-8");
|
|
157
|
-
return dataArray
|
|
166
|
+
return dataArray
|
|
167
|
+
.map((data) => injectData(loopTemplate, data, customFunctions))
|
|
168
|
+
.join("");
|
|
158
169
|
} catch (error) {
|
|
159
170
|
console.error(`Failed to include file: ${loopPath}`);
|
|
160
171
|
return "";
|
|
@@ -168,7 +179,8 @@ function processConditionals(
|
|
|
168
179
|
ifPattern,
|
|
169
180
|
includePattern,
|
|
170
181
|
loopPattern,
|
|
171
|
-
context
|
|
182
|
+
context,
|
|
183
|
+
customFunctions
|
|
172
184
|
) {
|
|
173
185
|
const regex = new RegExp(
|
|
174
186
|
`${ifPattern}\\s*\\(([^)]+)\\)\\s*{([\\s\\S]*?)};\\s*`,
|
|
@@ -177,11 +189,7 @@ function processConditionals(
|
|
|
177
189
|
|
|
178
190
|
return content.replace(regex, (match, condition, body) => {
|
|
179
191
|
try {
|
|
180
|
-
const
|
|
181
|
-
"data",
|
|
182
|
-
"with (data) { return " + condition + "; }"
|
|
183
|
-
);
|
|
184
|
-
const result = func(context);
|
|
192
|
+
const result = evaluateCondition(condition, context, customFunctions);
|
|
185
193
|
|
|
186
194
|
if (result) {
|
|
187
195
|
return processIncludesWithPattern(
|
|
@@ -190,7 +198,8 @@ function processConditionals(
|
|
|
190
198
|
includePattern,
|
|
191
199
|
loopPattern,
|
|
192
200
|
ifPattern,
|
|
193
|
-
context
|
|
201
|
+
context,
|
|
202
|
+
customFunctions
|
|
194
203
|
);
|
|
195
204
|
}
|
|
196
205
|
|
|
@@ -203,10 +212,10 @@ function processConditionals(
|
|
|
203
212
|
});
|
|
204
213
|
}
|
|
205
214
|
|
|
206
|
-
function injectData(content, data) {
|
|
215
|
+
function injectData(content, data, customFunctions = {}) {
|
|
207
216
|
return content.replace(/\{\{\s*(.*?)\s*\}\}/g, (match, expression) => {
|
|
208
217
|
try {
|
|
209
|
-
const result =
|
|
218
|
+
const result = evaluateExpression(expression, data, customFunctions);
|
|
210
219
|
return result !== undefined ? result : match;
|
|
211
220
|
} catch (error) {
|
|
212
221
|
console.error(`Failed to evaluate expression: ${expression}`);
|
|
@@ -216,12 +225,22 @@ function injectData(content, data) {
|
|
|
216
225
|
});
|
|
217
226
|
}
|
|
218
227
|
|
|
219
|
-
function
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
228
|
+
function evaluateExpression(expression, data, customFunctions) {
|
|
229
|
+
// Bind custom functions to the evaluation context
|
|
230
|
+
const context = { ...data, ...customFunctions };
|
|
231
|
+
return new Function(
|
|
232
|
+
"context",
|
|
233
|
+
"with (context) { return " + expression + "; }"
|
|
234
|
+
)(context);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
function evaluateCondition(condition, context, customFunctions) {
|
|
238
|
+
// Bind custom functions to the evaluation context
|
|
239
|
+
const contextWithFunctions = { ...context, ...customFunctions };
|
|
240
|
+
return new Function(
|
|
241
|
+
"context",
|
|
242
|
+
"with (context) { return " + condition + "; }"
|
|
243
|
+
)(contextWithFunctions);
|
|
225
244
|
}
|
|
226
245
|
|
|
227
|
-
export default
|
|
246
|
+
export default fileIncludePlugin;
|