@ynode/squirrellyify 1.5.2 → 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.
Files changed (2) hide show
  1. package/package.json +1 -1
  2. package/src/plugin.js +57 -19
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ynode/squirrellyify",
3
- "version": "1.5.2",
3
+ "version": "1.6.0",
4
4
  "description": "Fastify plugin for rendering Squirrelly templates.",
5
5
  "main": "src/plugin.js",
6
6
  "type": "module",
package/src/plugin.js CHANGED
@@ -38,7 +38,12 @@ import {
38
38
  resolveUseCache,
39
39
  validatePluginOptions,
40
40
  } from "./config.js";
41
- import { buildTemplateSearchDirs, collectViewScope, createTemplateResolver, preloadPartials } from "./resolver.js";
41
+ import {
42
+ buildTemplateSearchDirs,
43
+ collectViewScope,
44
+ createTemplateResolver,
45
+ preloadPartials,
46
+ } from "./resolver.js";
42
47
  import { createRuntimeApi } from "./runtime-api.js";
43
48
  import { assertSafeName } from "./safety.js";
44
49
 
@@ -75,7 +80,9 @@ async function squirrellyify(fastify, options = {}) {
75
80
  }
76
81
 
77
82
  const log =
78
- typeof fastify.log?.child === "function" ? fastify.log.child({ name: "@ynode/squirrellyify" }) : fastify.log;
83
+ typeof fastify.log?.child === "function"
84
+ ? fastify.log.child({ name: "@ynode/squirrellyify" })
85
+ : fastify.log;
79
86
 
80
87
  const initialTemplatesDirs = resolveInitialTemplateDirs(options);
81
88
  const initialPartialsDirs = resolveInitialPartialsDirs(options);
@@ -83,11 +90,17 @@ async function squirrellyify(fastify, options = {}) {
83
90
  const { extensionWithDot } = resolveExtension(options);
84
91
  const useCache = resolveUseCache(options);
85
92
  const { sqrlScope, sqrlConfig } = resolveSqrlConfig(options);
86
- const { defineSqrlHelper, defineSqrlFilter, defineSqrlTemplate, viewHelpers, viewFilters, viewPartials } =
87
- createRuntimeApi({
88
- sqrlScope,
89
- sqrlConfig,
90
- });
93
+ const {
94
+ defineSqrlHelper,
95
+ defineSqrlFilter,
96
+ defineSqrlTemplate,
97
+ viewHelpers,
98
+ viewFilters,
99
+ viewPartials,
100
+ } = createRuntimeApi({
101
+ sqrlScope,
102
+ sqrlConfig,
103
+ });
91
104
 
92
105
  if (options.sqrl?.helpers) {
93
106
  Object.entries(options.sqrl.helpers).forEach(([name, fn]) => {
@@ -110,12 +123,13 @@ async function squirrellyify(fastify, options = {}) {
110
123
  sqrlConfig,
111
124
  });
112
125
 
113
- const { findTemplatePath, getTemplate, hasLayoutTag, clearCaches, cacheStats } = createTemplateResolver({
114
- fastify,
115
- extensionWithDot,
116
- useCache,
117
- sqrlConfig,
118
- });
126
+ const { findTemplatePath, getTemplate, hasLayoutTag, clearCaches, cacheStats } =
127
+ createTemplateResolver({
128
+ fastify,
129
+ extensionWithDot,
130
+ useCache,
131
+ sqrlConfig,
132
+ });
119
133
 
120
134
  /**
121
135
  * Renders a Squirrelly template and sends it as an HTML response.
@@ -126,7 +140,8 @@ async function squirrellyify(fastify, options = {}) {
126
140
  async function view(template, data = {}) {
127
141
  try {
128
142
  const requestData = data && typeof data === "object" ? data : {};
129
- const replyContext = this.context && typeof this.context === "object" ? this.context : {};
143
+ const replyContext =
144
+ this.context && typeof this.context === "object" ? this.context : {};
130
145
  const replyLocals = this.locals && typeof this.locals === "object" ? this.locals : {};
131
146
  const mergedData = {
132
147
  ...replyContext,
@@ -141,12 +156,17 @@ async function squirrellyify(fastify, options = {}) {
141
156
 
142
157
  const instance = this.request.server;
143
158
  const { aggregatedTemplatesDirs, scopedLayout } = collectViewScope(instance);
144
- const templateSearchDirs = buildTemplateSearchDirs(aggregatedTemplatesDirs, initialTemplatesDirs);
159
+ const templateSearchDirs = buildTemplateSearchDirs(
160
+ aggregatedTemplatesDirs,
161
+ initialTemplatesDirs,
162
+ );
145
163
 
146
164
  // 1. Find and render the page template
147
165
  const pagePath = await findTemplatePath(template, templateSearchDirs);
148
166
  if (!pagePath) {
149
- throw new Error(`Template "${template}" not found in [${templateSearchDirs.join(", ")}]`);
167
+ throw new Error(
168
+ `Template "${template}" not found in [${templateSearchDirs.join(", ")}]`,
169
+ );
150
170
  }
151
171
 
152
172
  const pageTemplate = await getTemplate(pagePath);
@@ -154,7 +174,8 @@ async function squirrellyify(fastify, options = {}) {
154
174
 
155
175
  // 2. Determine which layout to use
156
176
  const currentLayout = scopedLayout !== null ? scopedLayout : initialLayout;
157
- const layoutFile = mergedData.layout === false ? null : mergedData.layout || currentLayout;
177
+ const layoutFile =
178
+ mergedData.layout === false ? null : mergedData.layout || currentLayout;
158
179
 
159
180
  if (!layoutFile) {
160
181
  return this.type("text/html").send(pageHtml);
@@ -167,12 +188,16 @@ async function squirrellyify(fastify, options = {}) {
167
188
  // 3. Find and render the layout, injecting the page content
168
189
  const layoutPath = await findTemplatePath(layoutFile, templateSearchDirs);
169
190
  if (!layoutPath) {
170
- throw new Error(`Layout "${layoutFile}" not found in [${templateSearchDirs.join(", ")}]`);
191
+ throw new Error(
192
+ `Layout "${layoutFile}" not found in [${templateSearchDirs.join(", ")}]`,
193
+ );
171
194
  }
172
195
 
173
196
  const layoutTemplate = await getTemplate(layoutPath);
174
197
  const layoutPayload =
175
- mergedData.layoutData && typeof mergedData.layoutData === "object" ? mergedData.layoutData : {};
198
+ mergedData.layoutData && typeof mergedData.layoutData === "object"
199
+ ? mergedData.layoutData
200
+ : {};
176
201
  const layoutData = { ...mergedData, ...layoutPayload, body: pageHtml };
177
202
  const finalHtml = await layoutTemplate(layoutData, sqrlConfig);
178
203
 
@@ -189,6 +214,19 @@ async function squirrellyify(fastify, options = {}) {
189
214
  }
190
215
  }
191
216
 
217
+ // Pre-decorate context for V8 optimization performance in consumers
218
+ try {
219
+ fastify.decorateReply("context", null);
220
+ } catch (err) {
221
+ if (err.code !== "FST_ERR_DEC_ALREADY_PRESENT") {
222
+ throw err;
223
+ }
224
+ }
225
+
226
+ fastify.addHook("onRequest", async (request, reply) => {
227
+ reply.context = {};
228
+ });
229
+
192
230
  // Decorate the reply object with the main view function
193
231
  fastify.decorateReply("view", view);
194
232