/
flags.ts
228 lines (219 loc) · 8.26 KB
/
flags.ts
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
import _ from "lodash"
import semver from "semver"
import sampleSiteForExperiment from "./sample-site-for-experiment"
// Does this experiment run for only builds
type executingCommand = "build" | "develop" | "all"
export const satisfiesSemvers = (
semverConstraints: Record<string, string>
): boolean => {
// Check each semver check for the flag.
// If any are false, then the flag doesn't pass
const result = _.toPairs(semverConstraints).every(
([packageName, semverConstraint]) => {
let packageVersion: string
try {
packageVersion = require(`${packageName}/package.json`).version
} catch (e) {
return false
}
// We care if the semver check doesn't pass.
return semver.satisfies(packageVersion, semverConstraint, {
includePrerelease: true,
})
}
)
return result
}
export type fitnessEnum = true | false | "OPT_IN" | "LOCKED_IN"
export interface IFlag {
name: string
env: string
description: string
command: executingCommand
/**
* Use string identifier to track enabled flag or false to disable any tracking (useful when flag becomes new defaults)
*/
telemetryId: string | false
// Heuristics for deciding if a flag is experimental:
// - there are known bugs most people will encounter and that block being
// able to use Gatsby normally
// - very few people have tested the feature so we're not sure if we've
// uncovered even common problems.
//
// Flags should start as experimental but once all serious known bugs are
// resolved and ~50+ people have tested it, experimental should be set to
// false.
experimental: boolean
/**
* True means conditions for the feature are met and can be opted in by user.
*
* False means it'll be disabled despite the user setting it true e.g.
* it just won't work e.g. it doesn't have new enough version for something.
*
* OPT_IN means the gatsby will enable the flag (unless the user explicitly
* disables it.
*
* LOCKED_IN means that feature is enabled always (unless `noCI` condition is met).
* This is mostly to provide more meaningful terminal messages instead of removing
* flag from the flag list when users has the flag set in configuration
* (avoids showing unknown flag message and shows "no longer needed" message).
*/
testFitness: (flag: IFlag) => fitnessEnum
/**
* Human-readable text explaining requirements for this feature to be available
* (e.g. requires Node 14+)
*
* It is shown to users when testFitness() returns `false` but flag is set in gatsby-config.js
*/
requires?: string
includedFlags?: Array<string>
umbrellaIssue?: string
noCI?: boolean
}
const activeFlags: Array<IFlag> = [
{
name: `FAST_DEV`,
env: `GATSBY_EXPERIMENTAL_FAST_DEV`,
command: `develop`,
telemetryId: `FastDev`,
experimental: false,
description: `Enable all experiments aimed at improving develop server start time.`,
includedFlags: [
`DEV_SSR`,
`PRESERVE_FILE_DOWNLOAD_CACHE`,
`DEV_WEBPACK_CACHE`,
],
testFitness: (): fitnessEnum => true,
},
{
name: `DEV_SSR`,
env: `GATSBY_EXPERIMENTAL_DEV_SSR`,
command: `develop`,
telemetryId: `DevSsr`,
experimental: false,
description: `Server Side Render (SSR) pages on full reloads during develop. Helps you detect SSR bugs and fix them without needing to do full builds. See umbrella issue for how to update custom webpack config.`,
umbrellaIssue: `https://gatsby.dev/dev-ssr-feedback`,
testFitness: (): fitnessEnum => {
if (sampleSiteForExperiment(`DEV_SSR`, 20)) {
return `OPT_IN`
} else {
return true
}
},
},
{
name: `QUERY_ON_DEMAND`,
env: `GATSBY_EXPERIMENTAL_QUERY_ON_DEMAND`,
command: `develop`,
telemetryId: false,
experimental: false,
description: `Only run queries when needed instead of running all queries upfront. Speeds starting the develop server.`,
umbrellaIssue: `https://gatsby.dev/query-on-demand-feedback`,
noCI: true,
testFitness: (): fitnessEnum => `LOCKED_IN`,
},
{
name: `LAZY_IMAGES`,
env: `GATSBY_EXPERIMENTAL_LAZY_IMAGES`,
command: `develop`,
telemetryId: false,
experimental: false,
description: `Don't process images during development until they're requested from the browser. Speeds starting the develop server. Requires gatsby-plugin-sharp@2.10.0 or above.`,
umbrellaIssue: `https://gatsby.dev/lazy-images-feedback`,
noCI: true,
testFitness: (): fitnessEnum => {
const semverConstraints = {
// Because of this, this flag will never show up
"gatsby-plugin-sharp": `>=2.10.0`,
}
if (satisfiesSemvers(semverConstraints)) {
return `LOCKED_IN`
} else {
// gatsby-plugin-sharp is either not installed or not new enough so
// just disable — it won't work anyways.
return false
}
},
requires: `Requires gatsby-plugin-sharp@2.10.0 or above.`,
},
{
name: `PRESERVE_WEBPACK_CACHE`,
env: `GATSBY_EXPERIMENTAL_PRESERVE_WEBPACK_CACHE`,
command: `all`,
telemetryId: `PreserveWebpackCache`,
experimental: false,
description: `Use webpack's persistent caching and don't delete webpack's cache when changing gatsby-node.js & gatsby-config.js files.`,
umbrellaIssue: `https://gatsby.dev/cache-clearing-feedback`,
testFitness: (): fitnessEnum => `LOCKED_IN`,
},
{
name: `DEV_WEBPACK_CACHE`,
env: `GATSBY_EXPERIMENTAL_DEV_WEBPACK_CACHE`,
command: `develop`,
telemetryId: `DevWebackCache`,
experimental: false,
description: `Enable webpack's persistent caching during development. Speeds up the start of the development server.`,
umbrellaIssue: `https://gatsby.dev/cache-clearing-feedback`,
testFitness: (): fitnessEnum => true,
},
{
name: `PRESERVE_FILE_DOWNLOAD_CACHE`,
env: `GATSBY_EXPERIMENTAL_PRESERVE_FILE_DOWNLOAD_CACHE`,
command: `all`,
telemetryId: `PreserveFileDownloadCache`,
experimental: false,
description: `Don't delete the downloaded files cache when changing gatsby-node.js & gatsby-config.js files.`,
umbrellaIssue: `https://gatsby.dev/cache-clearing-feedback`,
testFitness: (): fitnessEnum => true,
},
{
name: `PARALLEL_SOURCING`,
env: `GATSBY_EXPERIMENTAL_PARALLEL_SOURCING`,
command: `all`,
telemetryId: `ParallelSourcing`,
experimental: true,
description: `Run all source plugins at the same time instead of serially. For sites with multiple source plugins, this can speedup sourcing and transforming considerably.`,
umbrellaIssue: `https://gatsby.dev/parallel-sourcing-feedback`,
testFitness: (): fitnessEnum => true,
},
{
name: `FUNCTIONS`,
env: `GATSBY_EXPERIMENTAL_FUNCTIONS`,
command: `all`,
telemetryId: `Functions`,
experimental: false,
description: `Compile Serverless functions in your Gatsby project and write them to disk, ready to deploy to Gatsby Cloud`,
umbrellaIssue: `https://gatsby.dev/functions-feedback`,
testFitness: (): fitnessEnum => `LOCKED_IN`,
},
{
name: `LMDB_STORE`,
env: `GATSBY_EXPERIMENTAL_LMDB_STORE`,
command: `all`,
telemetryId: `LmdbStore`,
experimental: true,
umbrellaIssue: `https://gatsby.dev/lmdb-feedback`,
description: `Store nodes in a persistent embedded database (vs in-memory). Lowers peak memory usage. Requires Node v14.10 or above.`,
testFitness: (): fitnessEnum => {
const [major, minor] = process.versions.node.split(`.`)
return (Number(major) === 14 && Number(minor) >= 10) || Number(major) > 14
},
requires: `Requires Node v14.10 or above.`,
},
{
name: `PARALLEL_QUERY_RUNNING`,
env: `GATSBY_EXPERIMENTAL_PARALLEL_QUERY_RUNNING`,
command: `build`,
telemetryId: `PQR`,
experimental: true,
umbrellaIssue: `https://gatsby.dev/pqr-feedback`,
description: `Parallelize running page queries in order to better saturate all available cores. Improves time it takes to run queries during gatsby build. Requires Node v14.10 or above.`,
includedFlags: [`LMDB_STORE`],
testFitness: (): fitnessEnum => {
const [major, minor] = process.versions.node.split(`.`)
return (Number(major) === 14 && Number(minor) >= 10) || Number(major) > 14
},
requires: `Requires Node v14.10 or above.`,
},
]
export default activeFlags