Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
mastodon
GitHub Repository: mastodon/joinmastodon
Path: blob/main/next.config.ts
1006 views
1
import { NextConfig } from "next"
2
3
const { locales, defaultLocale } = require("./data/locales.js")
4
5
function notIfProduction(param) {
6
if (process.env.NODE_ENV === "production") return ""
7
else return param
8
}
9
10
const nextConfig: NextConfig = {
11
reactStrictMode: true,
12
i18n: {
13
locales: locales.map((l) => l.code),
14
defaultLocale,
15
},
16
images: {
17
remotePatterns: [
18
{ hostname: "proxy.joinmastodon.org" },
19
{ hostname: "c8.patreon.com" },
20
{ hostname: "c10.patreonusercontent.com" },
21
],
22
},
23
async headers() {
24
// These static files are references with hardcoded URLs and need proper Cache-Control headers
25
return ["/fonts/:all*(ttf|otf|woff|woff2)", "/:all*.png"]
26
.map((source) => ({
27
source,
28
headers: [
29
{
30
key: "Cache-control",
31
value: "max-age=3600, stale-while-revalidate",
32
},
33
],
34
}))
35
.concat(
36
{
37
source: "/(.*)?",
38
headers: [
39
{
40
key: "X-Content-Type-Options",
41
value: "nosniff",
42
},
43
{
44
key: "Permissions-Policy",
45
value:
46
"camera=(), microphone=(), geolocation=(), browsing-topics=()",
47
},
48
{
49
key: "Referrer-Policy",
50
value: "origin-when-cross-origin",
51
},
52
{
53
key: "Content-Security-Policy",
54
value: cspMapToString({
55
"default-src": ["self"],
56
"child-src": ["self"],
57
"object-src": ["none"],
58
"img-src": [
59
"self",
60
"proxy.joinmastodon.org",
61
"blob:",
62
"data:",
63
"https://queue.simpleanalyticscdn.com",
64
"https://simpleanalyticsbadges.com",
65
],
66
"style-src": ["self", "unsafe-inline"],
67
"script-src": [
68
"self",
69
notIfProduction("unsafe-inline"),
70
notIfProduction("unsafe-eval"),
71
"https://scripts.simpleanalyticscdn.com",
72
],
73
"connect-src": [
74
"self",
75
"api.joinmastodon.org",
76
"https://queue.simpleanalyticscdn.com",
77
"https://scripts.simpleanalyticscdn.com",
78
],
79
"block-all-mixed-content": [],
80
}),
81
},
82
],
83
},
84
{
85
source: "/donate/(.*)?",
86
headers: [
87
{
88
key: "Content-Security-Policy",
89
// Policies taken from: https://docs.stripe.com/security/guide?csp=csp-js
90
value: cspMapToString({
91
"default-src": ["self"],
92
"img-src": [
93
"self",
94
"proxy.joinmastodon.org",
95
"https://*.stripe.com",
96
"blob:",
97
"data:",
98
"https://queue.simpleanalyticscdn.com",
99
"https://simpleanalyticsbadges.com",
100
],
101
"style-src": ["self", "unsafe-inline"],
102
"script-src": [
103
"self",
104
notIfProduction("unsafe-inline"),
105
notIfProduction("unsafe-eval"),
106
"https://connect-js.stripe.com",
107
"https://js.stripe.com",
108
"https://*.js.stripe.com",
109
"https://maps.googleapis.com",
110
"https://scripts.simpleanalyticscdn.com",
111
],
112
"block-all-mixed-content": [],
113
"frame-src": [
114
"https://connect-js.stripe.com",
115
"https://js.stripe.com",
116
"https://*.js.stripe.com",
117
"https://hooks.stripe.com",
118
],
119
"connect-src": [
120
"self",
121
"https://api.stripe.com",
122
"https://maps.googleapis.com",
123
"https://queue.simpleanalyticscdn.com",
124
"https://scripts.simpleanalyticscdn.com",
125
],
126
}),
127
},
128
],
129
}
130
)
131
},
132
async redirects() {
133
return [
134
{
135
source: "/communities",
136
destination: "/servers",
137
permanent: true,
138
},
139
140
{
141
source: "/imprint",
142
destination: "/about#impressum",
143
permanent: true,
144
},
145
146
{
147
source: "/impressum",
148
destination: "/about#impressum",
149
permanent: true,
150
},
151
]
152
},
153
webpack(config) {
154
// Grab the existing rule that handles SVG imports
155
const fileLoaderRule = config.module.rules.find(
156
(rule) => rule.test && rule.test.test?.(".svg")
157
)
158
159
config.module.rules.push({
160
oneOf: [
161
// warning: do not specify `issuer` key here, it is broken with dynamic require
162
// see https://github.com/webpack/webpack/issues/9309
163
// https://github.com/vercel/next.js/discussions/15437
164
{
165
test: /\.svg$/i,
166
resourceQuery: /inline/, // Only for *.svg?inline
167
use: [{ loader: "@svgr/webpack", options: { svgo: false } }],
168
},
169
170
// we need to add this, as the previous rule disabled the default SVG loader
171
{
172
...fileLoaderRule,
173
test: /\.svg$/i,
174
resourceQuery: { not: [/inline/] },
175
},
176
],
177
})
178
179
// Modify the file loader rule to ignore *.svg, since we have it handled now.
180
fileLoaderRule.exclude = /\.svg$/i
181
return config
182
},
183
poweredByHeader: false,
184
output: "standalone",
185
eslint: {
186
dirs: ["."], // Check all files in the project
187
},
188
}
189
190
function cspMapToString(map: Record<string, string[]>) {
191
return Object.entries(map)
192
.map(([key, values]) => {
193
const valuesString = values
194
.filter(Boolean)
195
.map((value) =>
196
value.includes(".") || value.includes(":") ? value : `'${value}'`
197
)
198
.join(" ")
199
return `${key} ${valuesString}`
200
})
201
.join("; ")
202
}
203
204
module.exports = nextConfig
205
206