@serwist/turbopack 10.0.0-preview.10

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.
@@ -0,0 +1,278 @@
1
+ import type { RuntimeCaching } from "serwist";
2
+ import { CacheFirst, ExpirationPlugin, NetworkFirst, NetworkOnly, RangeRequestsPlugin, StaleWhileRevalidate } from "serwist";
3
+
4
+ export const PAGES_CACHE_NAME = {
5
+ rscPrefetch: "pages-rsc-prefetch",
6
+ rsc: "pages-rsc",
7
+ html: "pages",
8
+ } as const;
9
+
10
+ /**
11
+ * The default, recommended list of caching strategies for applications
12
+ * built with Next.js.
13
+ *
14
+ * @see https://serwist.pages.dev/docs/next/worker-exports#default-cache
15
+ */
16
+ export const defaultCache: RuntimeCaching[] =
17
+ process.env.NODE_ENV !== "production"
18
+ ? [
19
+ {
20
+ matcher: /.*/i,
21
+ handler: new NetworkOnly(),
22
+ },
23
+ ]
24
+ : [
25
+ {
26
+ matcher: /^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,
27
+ handler: new CacheFirst({
28
+ cacheName: "google-fonts-webfonts",
29
+ plugins: [
30
+ new ExpirationPlugin({
31
+ maxEntries: 4,
32
+ maxAgeSeconds: 365 * 24 * 60 * 60, // 365 days
33
+ maxAgeFrom: "last-used",
34
+ }),
35
+ ],
36
+ }),
37
+ },
38
+ {
39
+ matcher: /^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,
40
+ handler: new StaleWhileRevalidate({
41
+ cacheName: "google-fonts-stylesheets",
42
+ plugins: [
43
+ new ExpirationPlugin({
44
+ maxEntries: 4,
45
+ maxAgeSeconds: 7 * 24 * 60 * 60, // 7 days
46
+ maxAgeFrom: "last-used",
47
+ }),
48
+ ],
49
+ }),
50
+ },
51
+ {
52
+ matcher: /\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,
53
+ handler: new StaleWhileRevalidate({
54
+ cacheName: "static-font-assets",
55
+ plugins: [
56
+ new ExpirationPlugin({
57
+ maxEntries: 4,
58
+ maxAgeSeconds: 7 * 24 * 60 * 60, // 7 days
59
+ maxAgeFrom: "last-used",
60
+ }),
61
+ ],
62
+ }),
63
+ },
64
+ {
65
+ matcher: /\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,
66
+ handler: new StaleWhileRevalidate({
67
+ cacheName: "static-image-assets",
68
+ plugins: [
69
+ new ExpirationPlugin({
70
+ maxEntries: 64,
71
+ maxAgeSeconds: 30 * 24 * 60 * 60, // 30 days
72
+ maxAgeFrom: "last-used",
73
+ }),
74
+ ],
75
+ }),
76
+ },
77
+ {
78
+ matcher: /\/_next\/static.+\.js$/i,
79
+ handler: new CacheFirst({
80
+ cacheName: "next-static-js-assets",
81
+ plugins: [
82
+ new ExpirationPlugin({
83
+ maxEntries: 64,
84
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
85
+ maxAgeFrom: "last-used",
86
+ }),
87
+ ],
88
+ }),
89
+ },
90
+ {
91
+ matcher: /\/_next\/image\?url=.+$/i,
92
+ handler: new StaleWhileRevalidate({
93
+ cacheName: "next-image",
94
+ plugins: [
95
+ new ExpirationPlugin({
96
+ maxEntries: 64,
97
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
98
+ maxAgeFrom: "last-used",
99
+ }),
100
+ ],
101
+ }),
102
+ },
103
+ {
104
+ matcher: /\.(?:mp3|wav|ogg)$/i,
105
+ handler: new CacheFirst({
106
+ cacheName: "static-audio-assets",
107
+ plugins: [
108
+ new ExpirationPlugin({
109
+ maxEntries: 32,
110
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
111
+ maxAgeFrom: "last-used",
112
+ }),
113
+ new RangeRequestsPlugin(),
114
+ ],
115
+ }),
116
+ },
117
+ {
118
+ matcher: /\.(?:mp4|webm)$/i,
119
+ handler: new CacheFirst({
120
+ cacheName: "static-video-assets",
121
+ plugins: [
122
+ new ExpirationPlugin({
123
+ maxEntries: 32,
124
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
125
+ maxAgeFrom: "last-used",
126
+ }),
127
+ new RangeRequestsPlugin(),
128
+ ],
129
+ }),
130
+ },
131
+ {
132
+ matcher: /\.(?:js)$/i,
133
+ handler: new StaleWhileRevalidate({
134
+ cacheName: "static-js-assets",
135
+ plugins: [
136
+ new ExpirationPlugin({
137
+ maxEntries: 48,
138
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
139
+ maxAgeFrom: "last-used",
140
+ }),
141
+ ],
142
+ }),
143
+ },
144
+ {
145
+ matcher: /\.(?:css|less)$/i,
146
+ handler: new StaleWhileRevalidate({
147
+ cacheName: "static-style-assets",
148
+ plugins: [
149
+ new ExpirationPlugin({
150
+ maxEntries: 32,
151
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
152
+ maxAgeFrom: "last-used",
153
+ }),
154
+ ],
155
+ }),
156
+ },
157
+ {
158
+ matcher: /\/_next\/data\/.+\/.+\.json$/i,
159
+ handler: new NetworkFirst({
160
+ cacheName: "next-data",
161
+ plugins: [
162
+ new ExpirationPlugin({
163
+ maxEntries: 32,
164
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
165
+ maxAgeFrom: "last-used",
166
+ }),
167
+ ],
168
+ }),
169
+ },
170
+ {
171
+ matcher: /\.(?:json|xml|csv)$/i,
172
+ handler: new NetworkFirst({
173
+ cacheName: "static-data-assets",
174
+ plugins: [
175
+ new ExpirationPlugin({
176
+ maxEntries: 32,
177
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
178
+ maxAgeFrom: "last-used",
179
+ }),
180
+ ],
181
+ }),
182
+ },
183
+ {
184
+ matcher: ({ sameOrigin, url: { pathname } }) => {
185
+ // Exclude /api/auth/callback/* to fix OAuth workflow in Safari without having
186
+ // an impact on other environments
187
+ // The above route is the default for next-auth, you may need to change it if
188
+ // your OAuth workflow has a different callback route.
189
+ // Issue: https://github.com/shadowwalker/next-pwa/issues/131#issuecomment-821894809
190
+ // TODO(ducanhgh): Investigate Auth.js's "/api/auth/*" failing when we allow them
191
+ // to be cached (the current behaviour).
192
+ if (!sameOrigin || pathname.startsWith("/api/auth/callback")) {
193
+ return false;
194
+ }
195
+
196
+ if (pathname.startsWith("/api/")) {
197
+ return true;
198
+ }
199
+
200
+ return false;
201
+ },
202
+ method: "GET",
203
+ handler: new NetworkFirst({
204
+ cacheName: "apis",
205
+ plugins: [
206
+ new ExpirationPlugin({
207
+ maxEntries: 16,
208
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
209
+ maxAgeFrom: "last-used",
210
+ }),
211
+ ],
212
+ networkTimeoutSeconds: 10, // fallback to cache if API does not response within 10 seconds
213
+ }),
214
+ },
215
+ {
216
+ matcher: ({ request, url: { pathname }, sameOrigin }) =>
217
+ request.headers.get("RSC") === "1" && request.headers.get("Next-Router-Prefetch") === "1" && sameOrigin && !pathname.startsWith("/api/"),
218
+ handler: new NetworkFirst({
219
+ cacheName: PAGES_CACHE_NAME.rscPrefetch,
220
+ plugins: [
221
+ new ExpirationPlugin({
222
+ maxEntries: 32,
223
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
224
+ }),
225
+ ],
226
+ }),
227
+ },
228
+ {
229
+ matcher: ({ request, url: { pathname }, sameOrigin }) => request.headers.get("RSC") === "1" && sameOrigin && !pathname.startsWith("/api/"),
230
+ handler: new NetworkFirst({
231
+ cacheName: PAGES_CACHE_NAME.rsc,
232
+ plugins: [
233
+ new ExpirationPlugin({
234
+ maxEntries: 32,
235
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
236
+ }),
237
+ ],
238
+ }),
239
+ },
240
+ {
241
+ matcher: ({ request, url: { pathname }, sameOrigin }) =>
242
+ request.headers.get("Content-Type")?.includes("text/html") && sameOrigin && !pathname.startsWith("/api/"),
243
+ handler: new NetworkFirst({
244
+ cacheName: PAGES_CACHE_NAME.html,
245
+ plugins: [
246
+ new ExpirationPlugin({
247
+ maxEntries: 32,
248
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
249
+ }),
250
+ ],
251
+ }),
252
+ },
253
+ {
254
+ matcher: ({ url: { pathname }, sameOrigin }) => sameOrigin && !pathname.startsWith("/api/"),
255
+ handler: new NetworkFirst({
256
+ cacheName: "others",
257
+ plugins: [
258
+ new ExpirationPlugin({
259
+ maxEntries: 32,
260
+ maxAgeSeconds: 24 * 60 * 60, // 24 hours
261
+ }),
262
+ ],
263
+ }),
264
+ },
265
+ {
266
+ matcher: ({ sameOrigin }) => !sameOrigin,
267
+ handler: new NetworkFirst({
268
+ cacheName: "cross-origin",
269
+ plugins: [
270
+ new ExpirationPlugin({
271
+ maxEntries: 32,
272
+ maxAgeSeconds: 60 * 60, // 1 hour
273
+ }),
274
+ ],
275
+ networkTimeoutSeconds: 10,
276
+ }),
277
+ },
278
+ ];
@@ -0,0 +1,4 @@
1
+ export const DEFAULT_GLOB_PATTERNS = [
2
+ ".next/static/**/*.{js,css,html,ico,apng,png,avif,jpg,jpeg,jfif,pjpeg,pjp,gif,svg,webp,json,webmanifest}",
3
+ "public/**/*",
4
+ ];
@@ -0,0 +1,16 @@
1
+ import type { Serwist } from "@serwist/window";
2
+ import { createContext, useContext } from "react";
3
+
4
+ export interface SerwistContextValues {
5
+ serwist: Serwist | null;
6
+ }
7
+
8
+ export const SerwistContext = createContext<SerwistContextValues>(null!);
9
+
10
+ export const useSerwist = () => {
11
+ const context = useContext(SerwistContext);
12
+ if (!context) {
13
+ throw new Error("[useSerwist]: 'SerwistContext' is not available.");
14
+ }
15
+ return context;
16
+ };
@@ -0,0 +1,3 @@
1
+ import * as logger from "./logger.js";
2
+
3
+ export { logger };
@@ -0,0 +1,57 @@
1
+ import { bold, green, red, white, yellow } from "kolorist";
2
+
3
+ const LOGGING_METHOD = ["wait", "error", "warn", "info", "event"] as const;
4
+
5
+ type LoggingMethods = (typeof LOGGING_METHOD)[number];
6
+
7
+ const mapLoggingMethodToConsole: Record<LoggingMethods, "log" | "error" | "warn" | "log"> = {
8
+ wait: "log",
9
+ error: "error",
10
+ warn: "warn",
11
+ info: "log",
12
+ event: "log",
13
+ };
14
+
15
+ const prefixes = {
16
+ wait: `${white(bold("○"))} (serwist)`,
17
+ error: `${red(bold("X"))} (serwist)`,
18
+ warn: `${yellow(bold("⚠"))} (serwist)`,
19
+ info: `${white(bold("○"))} (serwist)`,
20
+ event: `${green(bold("✓"))} (serwist)`,
21
+ };
22
+
23
+ const prefixedLog = (prefixType: LoggingMethods, ...message: any[]) => {
24
+ const consoleMethod = mapLoggingMethodToConsole[prefixType];
25
+ const prefix = prefixes[prefixType];
26
+
27
+ if ((message[0] === "" || message[0] === undefined) && message.length === 1) {
28
+ message.shift();
29
+ }
30
+
31
+ // If there's no message, don't print the prefix but a new line
32
+ if (message.length === 0) {
33
+ console[consoleMethod]("");
34
+ } else {
35
+ console[consoleMethod](` ${prefix}`, ...message);
36
+ }
37
+ };
38
+
39
+ export const wait = (...message: any[]) => {
40
+ prefixedLog("wait", ...message);
41
+ };
42
+
43
+ export const error = (...message: any[]) => {
44
+ prefixedLog("error", ...message);
45
+ };
46
+
47
+ export const warn = (...message: any[]) => {
48
+ prefixedLog("warn", ...message);
49
+ };
50
+
51
+ export const info = (...message: any[]) => {
52
+ prefixedLog("info", ...message);
53
+ };
54
+
55
+ export const event = (...message: any[]) => {
56
+ prefixedLog("event", ...message);
57
+ };
package/src/types.ts ADDED
@@ -0,0 +1,37 @@
1
+ import type {
2
+ BasePartial,
3
+ BaseResolved,
4
+ GlobPartial,
5
+ GlobResolved,
6
+ InjectPartial,
7
+ InjectResolved,
8
+ OptionalGlobDirectoryPartial,
9
+ RequiredGlobDirectoryResolved,
10
+ } from "@serwist/build";
11
+ import { assertType, type Equals } from "@serwist/build/schema";
12
+ import type { Prettify } from "@serwist/utils";
13
+ import type z from "zod";
14
+ import type { injectManifestOptions } from "./index.schema.js";
15
+
16
+ export interface TurboPartial {
17
+ /**
18
+ * The path to your working directory.
19
+ *
20
+ * @default process.cwd()
21
+ */
22
+ cwd?: string;
23
+ /**
24
+ * The Next.js `basePath` config option. If this option
25
+ * is not configured, set to `/`.
26
+ */
27
+ basePath: string;
28
+ }
29
+
30
+ export type TurboResolved = Required<TurboPartial>;
31
+
32
+ export type InjectManifestOptions = Prettify<BasePartial & GlobPartial & InjectPartial & OptionalGlobDirectoryPartial & TurboPartial>;
33
+
34
+ export type InjectManifestOptionsComplete = Prettify<BaseResolved & GlobResolved & InjectResolved & RequiredGlobDirectoryResolved & TurboResolved>;
35
+
36
+ assertType<Equals<InjectManifestOptions, z.input<typeof injectManifestOptions>>>();
37
+ assertType<Equals<InjectManifestOptionsComplete, z.output<typeof injectManifestOptions>>>();