-
-
Notifications
You must be signed in to change notification settings - Fork 0
/
next.config.js
289 lines (261 loc) · 15.2 KB
/
next.config.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
const bundleAnalyzer = require('@next/bundle-analyzer');
const nextSourceMaps = require('@zeit/next-source-maps');
const packageJson = require('./package');
const i18nConfig = require('./src/modules/core/i18n/i18nConfig');
const withSourceMaps = nextSourceMaps();
const withBundleAnalyzer = bundleAnalyzer({ // Run with "yarn analyse:bundle" - See https://www.npmjs.com/package/@next/bundle-analyzer
enabled: process.env.ANALYZE_BUNDLE === 'true',
});
const supportedLocales = i18nConfig.supportedLocales.map((supportedLocale) => {
return supportedLocale.name;
});
const noRedirectBlacklistedPaths = ['_next', 'api']; // Paths that mustn't have rewrite applied to them, to avoid the whole app to behave inconsistently
const publicBasePaths = ['robots', 'static', 'favicon.ico']; // All items (folders, files) under /public directory should be added there, to avoid redirection when an asset isn't found
const noRedirectBasePaths = [...supportedLocales, ...publicBasePaths, ...noRedirectBlacklistedPaths]; // Will disable url rewrite for those items (should contain all supported languages and all public base paths)
const date = new Date();
const GIT_COMMIT_SHA_SHORT = process.env.GIT_COMMIT_SHA.substring(0, 8);
console.debug(`Building Next with NODE_ENV="${process.env.NODE_ENV}" NEXT_PUBLIC_APP_STAGE="${process.env.NEXT_PUBLIC_APP_STAGE}" for NEXT_PUBLIC_CUSTOMER_REF="${process.env.NEXT_PUBLIC_CUSTOMER_REF}" using GIT_COMMIT_SHA=${process.env.GIT_COMMIT_SHA} and GIT_COMMIT_REF=${process.env.GIT_COMMIT_REF}`);
// We use `filter` to make sure there are not empty element.
// Default value is an empty array.
const GIT_COMMIT_TAGS = process.env.GIT_COMMIT_TAGS ? process.env.GIT_COMMIT_TAGS.trim() : '';
console.debug(`Deployment will be tagged automatically, using GIT_COMMIT_TAGS: "${GIT_COMMIT_TAGS}"`);
// Iterate over all tags and extract the first the match "v*"
const APP_RELEASE_TAG = GIT_COMMIT_TAGS ? GIT_COMMIT_TAGS.split(' ').find((tag) => tag.startsWith('v')) : `unknown-${GIT_COMMIT_SHA_SHORT}`;
console.debug(`Release version resolved from tags: "${APP_RELEASE_TAG}" (matching first tag starting with "v")`);
/**
* This file is for advanced configuration of the Next.js framework.
*
* The below config applies to the whole application.
* next.config.js gets used by the Next.js server and build phases, and it's not included in the browser build.
*
* XXX Not all configuration options are listed below, we only kept those of most interest.
* You'll need to dive into Next.js own documentation to find out about what's not included.
* Basically, we focused on options that seemed important for a SSG/SSR app running on serverless mode (Vercel).
* Also, we included some options by are not using them, this is mostly to help make you aware of those options, in case you'd need them.
*
* @see https://nextjs.org/docs/api-reference/next.config.js/introduction
*/
module.exports = withBundleAnalyzer(withSourceMaps({
// basepath: '', // If you want Next.js to cover only a subsection of the domain. See https://nextjs.org/docs/api-reference/next.config.js/basepath
// target: 'serverless', // Automatically enabled on Vercel, you may need to manually opt-in if you're not using Vercel. See https://nextjs.org/docs/api-reference/next.config.js/build-target#serverless-target
// trailingSlash: false, // By default Next.js will redirect urls with trailing slashes to their counterpart without a trailing slash. See https://nextjs.org/docs/api-reference/next.config.js/trailing-slash
/**
* React's Strict Mode is a development mode only feature for highlighting potential problems in an application.
* It helps to identify unsafe lifecycles, legacy API usage, and a number of other features.
*
* Officially suggested by Next.js:
* We strongly suggest you enable Strict Mode in your Next.js application to better prepare your application for the future of React.
*
* If you or your team are not ready to use Strict Mode in your entire application, that's OK! You can incrementally migrate on a page-by-page basis using <React.StrictMode>.
*
* @see https://nextjs.org/docs/api-reference/next.config.js/react-strict-mode
*/
// reactStrictMode: true, // XXX Disabled for now, but we should enable it
/**
* Environment variables added to JS bundle
*
* XXX All env variables defined in ".env*" files that aren't public (those that don't start with "NEXT_PUBLIC_") MUST manually be made available at build time below.
* They're necessary on Vercel for runtime execution (SSR, SSG with revalidate, everything that happens server-side will need those).
*
* XXX This is a duplication of the environment variables.
* The variables defined below are only used locally, while those in "vercel.*.json:build:env" will be used on the Vercel platform.
* See https://vercel.com/docs/v2/build-step/#providing-environment-variables
*
* @see https://nextjs.org/docs/api-reference/next.config.js/environment-variables
*/
env: {
GITHUB_DISPATCH_TOKEN: process.env.GITHUB_DISPATCH_TOKEN,
AIRTABLE_API_KEY: process.env.AIRTABLE_API_KEY,
AIRTABLE_BASE_ID: process.env.AIRTABLE_BASE_ID,
LOCIZE_API_KEY: process.env.LOCIZE_API_KEY,
SENTRY_DSN: process.env.SENTRY_DSN,
// Dynamic env variables
NEXT_PUBLIC_APP_BUILD_TIME: date.toString(),
NEXT_PUBLIC_APP_BUILD_TIMESTAMP: +date,
NEXT_PUBLIC_APP_NAME: packageJson.name,
NEXT_PUBLIC_APP_NAME_VERSION: `${packageJson.name}-${APP_RELEASE_TAG}`,
UNLY_SIMPLE_LOGGER_ENV: process.env.NEXT_PUBLIC_APP_STAGE, // Used by @unly/utils-simple-logger - Fix missing staging logs because otherwise it believes we're in production
GIT_COMMIT_SHA_SHORT,
GIT_COMMIT_SHA: process.env.GIT_COMMIT_SHA, // Resolve commit hash from ENV first (set through CI), fallbacks to reading git (when used locally, through "/scripts/populate-git-env.sh")
GIT_COMMIT_REF: process.env.GIT_COMMIT_REF, // Resolve commit ref (branch/tag) from ENV first (set through CI), fallbacks to reading git (when used locally, through "/scripts/populate-git-env.sh")
GIT_COMMIT_TAGS: process.env.GIT_COMMIT_TAGS || '', // Resolve commit tags/releases from ENV first (set through CI), fallbacks to reading git (when used locally, through "/scripts/populate-git-env.sh")
},
/**
* Headers allow you to set custom HTTP headers for an incoming request path.
*
* Headers allow you to set route specific headers like CORS headers, content-types, and any other headers that may be needed.
* They are applied at the very top of the routes.
*
* @return {Promise<Array<{ headers: [{value: string, key: string}], source: string }>>}
* @see https://nextjs.org/docs/api-reference/next.config.js/headers
* @since 9.5 - See https://nextjs.org/blog/next-9-5#headers
*/
async headers() {
const headers = [];
// XXX Forbid usage in iframes from external 3rd parties, for non-production site
// This is meant to avoid customers using the preview in their production website, which would incur uncontrolled costs on our end
// Also, our preview env cannot scale considering each request send many airtable API calls and those are rate limited and out of our control
if (process.env.NEXT_PUBLIC_APP_STAGE !== 'production') {
headers.push({
source: '/(.*?)', // Match all paths, including "/" - See https://github.com/vercel/next.js/discussions/17991#discussioncomment-112028
// source: '/:path*', // Match all paths, excluding "/"
headers: [
{
key: 'Content-Security-Policy',
value: 'frame-ancestors *.stacker.app',
},
],
});
}
console.info('Using headers:', JSON.stringify(headers, null, 2));
return headers;
},
/**
* Rewrites allow you to map an incoming request path to a different destination path.
*
* Rewrites are only available on the Node.js environment and do not affect client-side routing.
* Rewrites are the most commonly used form of custom routing — they're used for dynamic routes (pretty URLs), user-land routing libraries (e.g. next-routes), internationalization, and other advanced use cases.
*
* For example, the route /user/:id rendering a specific user's profile page is a rewrite.
* Rendering your company's about page for both /about and /fr/a-propos is also a rewrite.
* The destination url can be internal, or external.
*
* @return { Promise<Array<{ destination: string, source: string, headers: Array<{ key: string, value: string }> }>> }
* @see https://nextjs.org/docs/api-reference/next.config.js/rewrites
* @since 9.5 - See https://nextjs.org/blog/next-9-5#rewrites
*/
async rewrites() {
const rewrites = [
// I18n rewrites
{
// XXX Doesn't work locally (maybe because of rewrites), but works online
source: '/',
destination: '/api/autoRedirectToLocalisedPage',
},
{
source: `/:locale((?!${noRedirectBasePaths.join('|')})[^/]+)(.*)`,
destination: '/api/autoRedirectToLocalisedPage',
},
// Robots rewrites
{
source: `/robots.txt`,
destination: process.env.NEXT_PUBLIC_APP_STAGE === 'production' ? `/robots/production.txt` : '/robots/!production.txt',
},
];
console.info('Using rewrites:', rewrites);
return rewrites;
},
/**
* Redirects allow you to redirect an incoming request path to a different destination path.
*
* Redirects are only available on the Node.js environment and do not affect client-side routing.
* By redirects, we mean HTTP Redirects (aka URL forwarding).
* Redirects are most commonly used when a website is reorganized — ensuring search engines and bookmarks are forwarded to their new locations.
* The destination url can be internal, or external.
*
* @return { Promise<Array<{ permanent: boolean, destination: string, source: string, statusCode?: number }>> }
* @see https://nextjs.org/docs/api-reference/next.config.js/redirects
* @since 9.5 - See https://nextjs.org/blog/next-9-5#redirects
*/
async redirects() {
const redirects = [
// I18n redirects
{
// Redirect root link with trailing slash to non-trailing slash, avoids 404 - See https://github.com/vercel/next.js/discussions/10651#discussioncomment-8270
source: '/:locale/',
destination: '/:locale',
permanent: process.env.NEXT_PUBLIC_APP_STAGE !== 'development', // Do not use permanent redirect locally to avoid browser caching when working on it
},
{
// Redirect link with trailing slash to non-trailing slash (any depth), avoids 404 - See https://github.com/vercel/next.js/discussions/10651#discussioncomment-8270
source: '/:locale/:path*/',
destination: '/:locale/:path*',
permanent: process.env.NEXT_PUBLIC_APP_STAGE !== 'development', // Do not use permanent redirect locally to avoid browser caching when working on it
},
];
console.info('Using redirects:', redirects);
return redirects;
},
/**
*
* The webpack function is executed twice, once for the server and once for the client.
* This allows you to distinguish between client and server configuration using the isServer property.
*
* @param config Current webpack config. Useful to reuse parts of what's already configured while overridding other parts.
* @param buildId The build id, used as a unique identifier between builds.
* @param dev Indicates if the compilation will be done in development.
* @param isServer It's true for server-side compilation, and false for client-side compilation.
* @param defaultLoaders Default loaders used internally by Next.js:
* - babel Default babel-loader configuration
* @see https://nextjs.org/docs/api-reference/next.config.js/custom-webpack-config
*/
webpack: (config, { buildId, dev, isServer, defaultLoaders }) => {
if (isServer) {
// IS_SERVER_INITIAL_BUILD is meant to be defined only at build time and not at run time, and therefore must not be "made public"
process.env.IS_SERVER_INITIAL_BUILD = '1';
}
const APP_VERSION_RELEASE = APP_RELEASE_TAG || buildId;
config.plugins.map((plugin, i) => {
if (plugin.definitions) { // If it has a "definitions" key, then we consider it's the DefinePlugin where ENV vars are stored
// Dynamically add some "public env" variables that will be replaced during the build through "DefinePlugin"
// Those variables are considered public because they are available at build time and at run time (they'll be replaced during initial build, by their value)
plugin.definitions['process.env.NEXT_PUBLIC_APP_BUILD_ID'] = JSON.stringify(buildId);
plugin.definitions['process.env.NEXT_PUBLIC_APP_VERSION_RELEASE'] = JSON.stringify(APP_VERSION_RELEASE);
}
});
if (isServer) { // Trick to only log once
console.debug(`[webpack] Building release "${APP_VERSION_RELEASE}" using NODE_ENV="${process.env.NODE_ENV}" ${process.env.IS_SERVER_INITIAL_BUILD ? 'with IS_SERVER_INITIAL_BUILD="1"' : ''}`);
}
// Fixes npm packages that depend on `fs` module
config.node = {
fs: 'empty',
};
// XXX See https://github.com/vercel/next.js/blob/canary/examples/with-sentry-simple/next.config.js
// In `pages/_app.js`, Sentry is imported from @sentry/node. While
// @sentry/browser will run in a Node.js environment, @sentry/node will use
// Node.js-only APIs to catch even more unhandled exceptions.
//
// This works well when Next.js is SSRing your page on a server with
// Node.js, but it is not what we want when your client-side bundle is being
// executed by a browser.
//
// Luckily, Next.js will call this webpack function twice, once for the
// server and once for the client. Read more:
// https://nextjs.org/docs#customizing-webpack-config
//
// So ask Webpack to replace @sentry/node imports with @sentry/browser when
// building the browser's bundle
if (!isServer) {
config.resolve.alias['@sentry/node'] = '@sentry/browser';
}
return config;
},
/**
* Next.js uses a constant id generated at build time to identify which version of your application is being served.
*
* This can cause problems in multi-server deployments when next build is ran on every server.
* In order to keep a static build id between builds you can provide your own build id.
*
* XXX We documented this function in case you might want to use it, but we aren't using it.
*
* @see https://nextjs.org/docs/api-reference/next.config.js/configuring-the-build-id
*/
// generateBuildId: async () => {
// // You can, for example, get the latest git commit hash here
// return 'my-build-id'
// },
/**
* Next.js exposes some options that give you some control over how the server will dispose or keep in memory built pages in development.
*
* XXX We documented this function in case you might want to use it, but we aren't using it.
*
* @see https://nextjs.org/docs/api-reference/next.config.js/configuring-onDemandEntries
*/
// onDemandEntries: {
// // period (in ms) where the server will keep pages in the buffer
// maxInactiveAge: 25 * 1000,
// // number of pages that should be kept simultaneously without being disposed
// pagesBufferLength: 2,
// },
poweredByHeader: false, // See https://nextjs.org/docs/api-reference/next.config.js/disabling-x-powered-by
}));