@arponascension/express-inertia 1.5.1 → 1.6.0

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 CHANGED
@@ -8,7 +8,7 @@
8
8
 
9
9
  **@arponascension/express-inertia** is a production-ready **Inertia.js adapter for Express.js**. It brings the official [Inertia.js](https://inertiajs.com) protocol to **Node.js and Express** apps so you can build modern **single-page applications (SPAs)** with **Vue 3**, **React**, or **Svelte** using classic server-side routing and controllers — without the complexity of a REST API or a client-side router.
10
10
 
11
- It ships with a **Blade-style EJS template engine**, **zero-config Vite** integration (HMR in development, hashed `manifest.json` in production), **server-side rendering (SSR)** with circuit-breaker resilience, **security hardening**, **edge-runtime support** (Cloudflare Workers, Vercel Edge, Netlify Edge), and **first-class TypeScript** types — all in a tree-shakeable ~40KB bundle.
11
+ It ships with a **native EJS template engine** with Inertia/Vite helpers, **zero-config Vite** integration (HMR in development, hashed `manifest.json` in production), **server-side rendering (SSR)** with circuit-breaker resilience, **security hardening**, **edge-runtime support** (Cloudflare Workers, Vercel Edge, Netlify Edge), and **first-class TypeScript** types — all in a tree-shakeable ~40KB bundle.
12
12
 
13
13
  > New to Inertia.js? Read [What is Inertia.js?](#what-is-inertiajs) or the [official documentation](https://inertiajs.com/docs).
14
14
 
@@ -22,7 +22,7 @@ It ships with a **Blade-style EJS template engine**, **zero-config Vite** integr
22
22
  - [Installation](#installation)
23
23
  - [Quick Start: Express + Inertia + Vue 3](#quick-start-express--inertia--vue-3)
24
24
  - [Using Inertia.js with React](#using-inertiajs-with-react)
25
- - [Blade-style EJS Directives for Express](#blade-style-ejs-directives-for-express)
25
+ - [EJS Template Helpers for Express](#ejs-template-helpers-for-express)
26
26
  - [Vite Integration for Express](#vite-integration-for-express)
27
27
  - [Server-Side Rendering (SSR) for SEO](#server-side-rendering-ssr-for-seo)
28
28
  - [Response API: `res.inertia()`](#response-api-resinertia)
@@ -60,7 +60,7 @@ Inertia requests return plain JSON to the client (no full page reloads); real fu
60
60
 
61
61
  | Feature | What you get |
62
62
  |---|---|
63
- | **Blade-style EJS directives** | Write Laravel Blade syntax (`@inertia`, `@vite`, `@csrf`, `@inertiaHead`) directly inside `.ejs` templates |
63
+ | **Native EJS template helpers** | Call `<%- inertia() %>`, `<%- vite('src/main.ts') %>`, `<%- csrf() %>`, and `<%- inertiaHead() %>` directly inside `.ejs` templates |
64
64
  | **Zero-config Vite integration** | Automatic HMR in development; hashed `manifest.json` asset resolution in production |
65
65
  | **Server-side rendering (SSR)** | Express + Inertia SSR endpoint proxying with retry/backoff and **circuit breaker** fallback to client rendering |
66
66
  | **Security hardening** | Component name validation against path traversal, `viewData` sanitization, SRI hash generation |
@@ -107,7 +107,7 @@ import { inertia, createInertiaEngine } from '@arponascension/express-inertia';
107
107
 
108
108
  const app = express();
109
109
 
110
- // Blade-compatible EJS view engine for Express
110
+ // EJS view engine with Inertia/Vite helpers for Express
111
111
  app.engine('ejs', createInertiaEngine());
112
112
  app.set('view engine', 'ejs');
113
113
  app.set('views', path.join(__dirname, 'views'));
@@ -147,12 +147,12 @@ app.listen(3000, () => console.log('Server running on http://localhost:3000'));
147
147
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
148
148
  <title inertia><%= page?.props?.title || 'App' %></title>
149
149
 
150
- @inertiaHead
151
- @vite('src/main.ts')
150
+ <%- inertiaHead() %>
151
+ <%- vite('src/main.ts') %>
152
152
  </head>
153
153
  <body>
154
- @inertia
155
- @csrf
154
+ <%- inertia() %>
155
+ <%- csrf() %>
156
156
  </body>
157
157
  </html>
158
158
  ```
@@ -179,13 +179,13 @@ import vue from '@vitejs/plugin-vue';
179
179
  import { inertiaVitePlugin } from '@arponascension/express-inertia/vite';
180
180
 
181
181
  export default defineConfig({
182
- plugins: [vue(), inertiaVitePlugin()],
183
- base: '/build/',
184
- build: { manifest: true, outDir: 'public/build' },
182
+ plugins: [vue(), inertiaVitePlugin({ input: 'src/main.ts', refresh: true })],
185
183
  });
186
184
  ```
187
185
 
188
- Start Express and Vite in separate terminals during development; `inertiaVitePlugin()` writes `public/hot` so the EJS root view automatically uses the Vite dev server. Run `vite build` before production deployment to write `public/build/.vite/manifest.json`.
186
+ Start Express and Vite in separate terminals during development; `inertiaVitePlugin()` writes `public/hot` so the EJS root view automatically uses the Vite dev server.
187
+
188
+ When an `input` is provided, the plugin **auto-configures the production build**: it sets `build.manifest`, `build.outDir` (default `public/build`), `build.rollupOptions.input`, and a command-aware `base` (root-relative in dev, `/build/` at build time) — so `vite build` emits `public/build/.vite/manifest.json` ready for Express with **zero manual Vite config**. The `refresh: true` option makes the browser full-reload when an EJS view under `views/` changes.
189
189
 
190
190
  ## Using Inertia.js with React
191
191
 
@@ -203,11 +203,11 @@ createInertiaApp({
203
203
  });
204
204
  ```
205
205
 
206
- For React, use a `.tsx` entrypoint in the root view and include `@viteReactRefresh` before `@vite`:
206
+ For React, use a `.tsx` entrypoint in the root view and include `<%- viteReactRefresh() %>` before `<%- vite('src/main.tsx') %>`:
207
207
 
208
208
  ```html
209
- @viteReactRefresh
210
- @vite('src/main.tsx')
209
+ <%- viteReactRefresh() %>
210
+ <%- vite('src/main.tsx') %>
211
211
  ```
212
212
 
213
213
  Replace the Vue plugin with `@vitejs/plugin-react` in `vite.config.ts` and keep the same `inertiaVitePlugin()`:
@@ -218,47 +218,64 @@ import react from '@vitejs/plugin-react';
218
218
  import { inertiaVitePlugin } from '@arponascension/express-inertia/vite';
219
219
 
220
220
  export default defineConfig({
221
- plugins: [react(), inertiaVitePlugin()],
222
- base: '/build/',
223
- build: { manifest: true, outDir: 'public/build' },
221
+ plugins: [react(), inertiaVitePlugin({ input: 'src/main.tsx', refresh: true })],
224
222
  });
225
223
  ```
226
224
 
227
225
  ---
228
226
 
229
- ## Blade-style EJS Directives for Express
227
+ ## EJS Template Helpers for Express
230
228
 
231
- Write Laravel Blade-style syntax inside EJS templates, powered by a custom Express view engine:
229
+ Call the Inertia and Vite helpers as normal EJS expressions, powered by a custom Express view engine:
232
230
 
233
- | Directive | Component Tag | Output |
234
- |---|---|---|
235
- | `@inertia` | `<x-inertia />` | Renders `<div id="app"></div><script data-page="app" type="application/json">` |
236
- | `@inertia('root')` | `<x-inertia id="root" />` | Custom root ID |
237
- | `@inertiaScript` | `<x-inertia-script />` | JSON script only (manual root container) |
238
- | `@inertiaHead` | `<x-inertia-head />` | Injects SSR `<head>` tags |
239
- | `@vite('src/main.ts')` | `<x-vite src="src/main.ts" />` | Dev HMR or production manifest |
240
- | `@viteReactRefresh` | `<x-vite-react-refresh />` | React Fast Refresh preamble |
241
- | `@csrf` | `<x-csrf />` | CSRF hidden input |
242
- | `@routes` | `<x-routes />` | Ziggy / route definitions |
243
- | `@json(myVar)` | — | Safely stringifies a JS object |
244
-
245
- ### Custom directives
231
+ | EJS helper | Output |
232
+ |---|---|
233
+ | `<%- inertia() %>` | Renders `<div id="app"></div><script data-page="app" type="application/json">` |
234
+ | `<%- inertia('root') %>` | Custom root ID |
235
+ | `<%- inertiaScript() %>` | JSON script only (manual root container) |
236
+ | `<%- inertiaHead() %>` | Injects SSR `<head>` tags |
237
+ | `<%- vite('src/main.ts') %>` | Dev HMR or production manifest |
238
+ | `<%- viteReactRefresh() %>` | React Fast Refresh preamble |
239
+ | `<%- csrf() %>` | CSRF hidden input |
240
+ | `<%- routes() %>` | Ziggy / route definitions |
241
+ | `<%- json(myVar) %>` | Safely stringifies a JS object |
242
+
243
+ ---
244
+
245
+ ## Vite Integration for Express
246
+
247
+ Auto-detects the Vite dev server via the hot file (`public/hot`) and reads `manifest.json` in production.
248
+
249
+ ### Zero-config: `inertiaVitePlugin({ input, refresh })`
250
+
251
+ The recommended setup requires nothing but your client entrypoint:
246
252
 
247
253
  ```ts
248
- import { registerDirective } from '@arponascension/express-inertia';
254
+ import { defineConfig } from 'vite';
255
+ import react from '@vitejs/plugin-react';
256
+ import { inertiaVitePlugin } from '@arponascension/express-inertia/vite';
249
257
 
250
- registerDirective('uppercase', (args) => `<%= (${args}).toUpperCase() %>`);
258
+ export default defineConfig({
259
+ plugins: [react(), inertiaVitePlugin({ input: 'src/main.tsx', refresh: true })],
260
+ });
251
261
  ```
252
262
 
253
- ---
263
+ | Option | Type | Default | Description |
264
+ |---|---|---|---|
265
+ | `input` | `string \| string[]` | — | Client entrypoint(s) for the build. When set, the plugin auto-configures the build: enables `build.manifest`, builds into `public/{buildDirectory}`, registers `build.rollupOptions.input`, and uses a command-aware `base` (root in dev, `/{buildDirectory}/` at build time so hashed asset URLs resolve against the Express static mount). |
266
+ | `refresh` | `boolean \| string \| string[]` | `false` | Auto full-page reload when a server-rendered template changes. `true` watches `views/**/*.ejs`; a glob string or array watches custom paths relative to the project root. |
267
+ | `buildDirectory` | `string` | `'build'` | Directory inside `public/` that Vite builds into. |
268
+ | `hotFile` | `string` | `'public/hot'` | Hot file written by the plugin in dev mode. |
269
+ | `devServerUrl` | `string` | resolved dev URL | Override for the URL written to the hot file. |
254
270
 
255
- ## Vite Integration for Express
271
+ ### Manual asset resolution
256
272
 
257
- Auto-detects the Vite dev server via the hot file (`public/hot`) and reads `manifest.json` in production:
273
+ If you prefer to configure the build or engine yourself, the `vite` option on `createInertiaEngine()` (or the `inertia()` middleware, which is ignored there and only consumed by the engine) still gives you full control:
258
274
 
259
275
  ```ts
260
- app.use(
261
- inertia({
276
+ app.engine(
277
+ 'ejs',
278
+ createInertiaEngine({
262
279
  vite: {
263
280
  publicDir: 'public',
264
281
  buildDir: 'build',
@@ -270,6 +287,20 @@ app.use(
270
287
  );
271
288
  ```
272
289
 
290
+ > For that manual route, configure the build yourself — and use a command-aware `base` (a static `base: '/build/'` would make the Vite dev server serve modules under `/build/`, breaking dev HMR):
291
+ >
292
+ > ```ts
293
+ > export default defineConfig(({ command }) => ({
294
+ > plugins: [react(), inertiaVitePlugin()],
295
+ > base: command === 'build' ? '/build/' : '/',
296
+ > build: {
297
+ > manifest: true,
298
+ > outDir: 'public/build',
299
+ > rollupOptions: { input: 'src/main.tsx' },
300
+ > },
301
+ > }));
302
+ > ```
303
+
273
304
  ### Prefetch and preload helpers
274
305
 
275
306
  ```ts
@@ -558,7 +589,7 @@ const delay = calculateBackoff(attempt, 200, 2000);
558
589
  | `inertia(options?)` | Inertia.js Express middleware factory |
559
590
  | `createInertia(options?)` | Same as `inertia`, explicit name |
560
591
  | `requestIdMiddleware()` | Assigns `req.id` for log correlation |
561
- | `createInertiaEngine(options?)` | EJS view engine with Blade support |
592
+ | `createInertiaEngine(options?)` | EJS view engine with Inertia/Vite helpers |
562
593
  | `inertiaEngine` | Default engine instance |
563
594
 
564
595
  ### Prop helpers
@@ -599,7 +630,7 @@ const delay = calculateBackoff(attempt, 200, 2000);
599
630
  | Export | Description |
600
631
  |---|---|
601
632
  | `createViteHelper(config?)` | Vite asset resolver |
602
- | `inertiaVitePlugin(opts?)` | Auto write/remove the Vite hot file |
633
+ | `inertiaVitePlugin(opts?)` | Vite plugin — hot file + auto build config (`input`, `refresh`, `buildDirectory`) |
603
634
  | `createPrefetchHelper(viteHelper)` | Prefetch/preload tag generator |
604
635
 
605
636
  ---
@@ -624,7 +655,7 @@ Yes. Enable `ssr: { enabled: true }` and point it at the official Inertia SSR se
624
655
 
625
656
  ### What template engine does express-inertia use?
626
657
 
627
- EJS, extended with Laravel Blade-style directives (`@inertia`, `@vite`, `@csrf`, `@inertiaHead`, and more). A custom `createInertiaEngine()` is provided so templates load through Express's normal view engine mechanism.
658
+ EJS. A custom `createInertiaEngine()` is provided so templates load through Express's normal view engine mechanism, with Inertia and Vite helpers exposed as template locals (`inertia()`, `vite()`, `csrf()`, `inertiaHead()`, and more).
628
659
 
629
660
  ### Is express-inertia compatible with edge runtimes?
630
661
 
package/dist/base.ejs CHANGED
@@ -4,11 +4,11 @@
4
4
  <meta charset="utf-8" />
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0" />
6
6
  <title inertia><%= typeof title !== 'undefined' ? title : (page && page.props && page.props.title ? page.props.title : 'App') %></title>
7
- @inertiaHead
8
- @viteReactRefresh
9
- @vite('src/main.js')
7
+ <%- inertiaHead() %>
8
+ <%- viteReactRefresh() %>
9
+ <%- vite('src/main.js') %>
10
10
  </head>
11
11
  <body class="font-sans antialiased bg-gray-50 text-gray-900">
12
- @inertia
12
+ <%- inertia() %>
13
13
  </body>
14
14
  </html>
package/dist/engine.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { c as Page, e as SSRResult, B as BladeEngineOptions } from './types-DgBPobaU.mjs';
1
+ import { b as Page, d as SSRResult, f as InertiaEngineOptions } from './types-BlUoEa9x.mjs';
2
2
  import 'express';
3
3
 
4
4
  interface TemplateLocals extends Record<string, any> {
@@ -9,11 +9,11 @@ interface TemplateLocals extends Record<string, any> {
9
9
  routes?: any;
10
10
  }
11
11
  /**
12
- * Creates an Express view engine with Blade directive support and built-in Inertia/Vite helpers.
12
+ * Creates an Express EJS view engine with built-in Inertia/Vite helpers.
13
13
  */
14
- declare function createInertiaEngine(options?: BladeEngineOptions): (filePath: string, rawOptions: Record<string, any>, callback: (err: Error | null, html?: string) => void) => void;
14
+ declare function createInertiaEngine(options?: InertiaEngineOptions): (filePath: string, rawOptions: Record<string, any>, callback: (err: Error | null, html?: string) => void) => void;
15
15
  /**
16
- * Default Inertia Blade EJS engine instance.
16
+ * Default Inertia EJS engine instance.
17
17
  */
18
18
  declare const inertiaEngine: (filePath: string, rawOptions: Record<string, any>, callback: (err: Error | null, html?: string) => void) => void;
19
19
  /**
package/dist/engine.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { c as Page, e as SSRResult, B as BladeEngineOptions } from './types-DgBPobaU.js';
1
+ import { b as Page, d as SSRResult, f as InertiaEngineOptions } from './types-BlUoEa9x.js';
2
2
  import 'express';
3
3
 
4
4
  interface TemplateLocals extends Record<string, any> {
@@ -9,11 +9,11 @@ interface TemplateLocals extends Record<string, any> {
9
9
  routes?: any;
10
10
  }
11
11
  /**
12
- * Creates an Express view engine with Blade directive support and built-in Inertia/Vite helpers.
12
+ * Creates an Express EJS view engine with built-in Inertia/Vite helpers.
13
13
  */
14
- declare function createInertiaEngine(options?: BladeEngineOptions): (filePath: string, rawOptions: Record<string, any>, callback: (err: Error | null, html?: string) => void) => void;
14
+ declare function createInertiaEngine(options?: InertiaEngineOptions): (filePath: string, rawOptions: Record<string, any>, callback: (err: Error | null, html?: string) => void) => void;
15
15
  /**
16
- * Default Inertia Blade EJS engine instance.
16
+ * Default Inertia EJS engine instance.
17
17
  */
18
18
  declare const inertiaEngine: (filePath: string, rawOptions: Record<string, any>, callback: (err: Error | null, html?: string) => void) => void;
19
19
  /**
package/dist/engine.js CHANGED
@@ -12,86 +12,6 @@ var path__default = /*#__PURE__*/_interopDefault(path);
12
12
 
13
13
  // src/engine.ts
14
14
 
15
- // src/directives.ts
16
- var customDirectives = {};
17
- function escapeJsString(str) {
18
- return str.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
19
- }
20
- function compileBladeDirectives(templateSource, localDirectives) {
21
- let compiled = templateSource;
22
- compiled = compiled.replace(
23
- /<x-inertia(\s[^>]*)?\s*(\/|><\/x-inertia>)/gi,
24
- (_match, attrs) => {
25
- const idMatch = attrs?.match(/id=(?:"([^"]*)"|'([^']*)')/);
26
- const id = idMatch ? idMatch[1] || idMatch[2] : void 0;
27
- return id ? `<%- inertia('${escapeJsString(id)}') %>` : `<%- inertia() %>`;
28
- }
29
- );
30
- compiled = compiled.replace(
31
- /<x-inertia-(?:script|data)(\s[^>]*)?\s*(\/|><\/x-inertia-(?:script|data)>)/gi,
32
- (_match, attrs) => {
33
- const idMatch = attrs?.match(/id=(?:"([^"]*)"|'([^']*)')/);
34
- const id = idMatch ? idMatch[1] || idMatch[2] : void 0;
35
- return id ? `<%- inertiaScript('${escapeJsString(id)}') %>` : `<%- inertiaScript() %>`;
36
- }
37
- );
38
- compiled = compiled.replace(
39
- /<x-inertia-head\s*(?:\/>|><\/x-inertia-head>)|<x-inertiaHead\s*(?:\/>|><\/x-inertiaHead>)/gi,
40
- "<%- inertiaHead() %>"
41
- );
42
- compiled = compiled.replace(
43
- /<x-vite(\s[^>]*)?\s*(?:\/>|><\/x-vite>)/gi,
44
- (_match, attrs) => {
45
- const srcMatch = attrs?.match(/(?:src|entries)=(?:"([^"]*)"|'([^']*)')/);
46
- const val = srcMatch ? srcMatch[1] || srcMatch[2] : "";
47
- if (val.startsWith("[") && val.endsWith("]")) {
48
- return `<%- vite(${val}) %>`;
49
- }
50
- return `<%- vite('${escapeJsString(val)}') %>`;
51
- }
52
- );
53
- compiled = compiled.replace(
54
- /<x-vite-react-refresh\s*(?:\/>|><\/x-vite-react-refresh>)|<x-viteReactRefresh\s*(?:\/>|><\/x-viteReactRefresh>)/gi,
55
- "<%- viteReactRefresh() %>"
56
- );
57
- compiled = compiled.replace(/<x-csrf\s*(?:\/>|><\/x-csrf>)/gi, "<%- csrf() %>");
58
- compiled = compiled.replace(
59
- /<x-routes(\s[^>]*)?\s*(?:\/>|><\/x-routes>)/gi,
60
- (_match, attrs) => {
61
- const groupMatch = attrs?.match(/group=(?:"([^"]*)"|'([^']*)')/);
62
- const group = groupMatch ? groupMatch[1] || groupMatch[2] : void 0;
63
- return group ? `<%- routes('${escapeJsString(group)}') %>` : `<%- routes() %>`;
64
- }
65
- );
66
- compiled = compiled.replace(/@inertiaHead\b/g, "<%- inertiaHead() %>");
67
- compiled = compiled.replace(/@(inertiaScript|inertiaData)(\([^)]*\))?(?!\w)/g, (_match, _d, args) => {
68
- return args ? `<%- inertiaScript${args} %>` : `<%- inertiaScript() %>`;
69
- });
70
- compiled = compiled.replace(/@inertia(\([^)]*\))?(?!\w)/g, (_match, args) => {
71
- return args ? `<%- inertia${args} %>` : `<%- inertia() %>`;
72
- });
73
- compiled = compiled.replace(/@viteReactRefresh\b/g, "<%- viteReactRefresh() %>");
74
- compiled = compiled.replace(/@vite\(([^)]*(?:\([^)]*\)[^)]*)*)\)/g, (_match, args) => {
75
- return `<%- vite(${args.trim()}) %>`;
76
- });
77
- compiled = compiled.replace(/@csrf\b/g, "<%- csrf() %>");
78
- compiled = compiled.replace(/@routes(\([^)]*\))?(?!\w)/g, (_match, args) => {
79
- return args ? `<%- routes${args} %>` : `<%- routes() %>`;
80
- });
81
- compiled = compiled.replace(/@json\(([^)]*(?:\([^)]*\)[^)]*)*)\)/g, (_match, args) => {
82
- return `<%- json(${args.trim()}) %>`;
83
- });
84
- const allDirectives = { ...customDirectives, ...localDirectives || {} };
85
- for (const [name, handler] of Object.entries(allDirectives)) {
86
- const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
87
- const pattern = new RegExp(`@${escapedName}(\\([^)]*(?:\\([^)]*\\)[^)]*)*\\))?(?!\\w)`, "g");
88
- compiled = compiled.replace(pattern, (_match, args) => {
89
- return handler(args ? args.slice(1, -1).trim() : "", {});
90
- });
91
- }
92
- return compiled;
93
- }
94
-
95
15
  // src/logger.ts
96
16
  var DEFAULT_PREFIX = "@arponascension/express-inertia";
97
17
  function createConsoleLogger(prefix) {
@@ -398,7 +318,7 @@ function createInertiaEngine(options) {
398
318
  const templateTimestamps = /* @__PURE__ */ new Map();
399
319
  engineCaches.add(templateCache);
400
320
  engineTimestamps.add(templateTimestamps);
401
- return function inertiaBladeEngine(filePath, rawOptions, callback) {
321
+ return function inertiaEjsEngine(filePath, rawOptions, callback) {
402
322
  try {
403
323
  const template = options?.templateSource;
404
324
  const hasTemplateSource = template !== void 0;
@@ -421,7 +341,7 @@ function createInertiaEngine(options) {
421
341
  }
422
342
  if (!compiledTemplate) {
423
343
  const templateSource = template !== void 0 ? template : fs__default.default.readFileSync(filePath, "utf-8");
424
- const compiledSource = options?.compileTemplate ? options.compileTemplate(templateSource) : compileBladeDirectives(templateSource, options?.directives);
344
+ const compiledSource = options?.compileTemplate ? options.compileTemplate(templateSource) : templateSource;
425
345
  compiledTemplate = ejs__default.default.compile(compiledSource, {
426
346
  filename: filePath,
427
347
  cache: false,