forked from firefox-devtools/profiler
-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.js
172 lines (161 loc) · 5.61 KB
/
server.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
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
// @noflow
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const http = require('node:http');
const config = require('./webpack.config');
const { oneLine, stripIndent } = require('common-tags');
const port = process.env.FX_PROFILER_PORT || 4242;
const host = process.env.FX_PROFILER_HOST || 'localhost';
const fs = require('fs');
const path = require('path');
const yargs = require('yargs');
const { hideBin } = require('yargs/helpers');
const argv = yargs(hideBin(process.argv))
.command('* [profile]', 'Open Firefox Profiler, on [profile] if included.')
.option('c', {
alias: 'config',
describe: 'Path to local webpack config',
type: 'string',
})
// Disabled --version flag since no version number in package.json.
.version(false)
.strict()
.parseSync();
config.cache = {
type: 'filesystem',
};
const serverConfig = {
allowedHosts: ['localhost', '.gitpod.io'],
host,
port,
// We disable hot reloading because this takes lot of CPU and memory in the
// case of the profiler, which is a quite heavy program.
hot: false,
liveReload: false,
// redirects all 404 requests to index.html
historyApiFallback: {
// Without any special rule about having a "." character in the URL request.
disableDotRule: true,
},
headers: {
// See res/_headers for more information about all these headers.
// /!\ Don't forget to keep it sync-ed with the headers here /!\
'X-Content-Type-Options': 'nosniff',
'X-XSS-Protection': '1; mode=block',
'X-Frame-Options': 'SAMEORIGIN',
'Referrer-Policy': 'same-origin',
'Content-Security-Policy': oneLine`
default-src 'self';
script-src
'self'
'wasm-unsafe-eval'
https://www.google-analytics.com;
style-src 'self' 'unsafe-inline' https://fonts.googleapis.com;
font-src 'self' https://fonts.gstatic.com;
img-src http: https: data:;
object-src 'none';
connect-src *;
frame-ancestors 'self';
form-action 'none'
`,
},
static: false,
client: {
// See https://github.com/firefox-devtools/profiler/pull/4598#issuecomment-1529260852
// for the root cause of an error happening at load time. For this reason we
// disable the webpack overlay. We may be able to revisit after moving to
// the React 18 new API.
overlay: false,
},
};
// Allow a local file to override various options.
let localConfigFile; // Set by readConfig() below.
const defaultLocalConfigPath = path.join(
__dirname,
'./webpack.local-config.js'
);
const readConfig = (localConfigPath) => {
const configRequirePath = `./${path.relative(__dirname, localConfigPath)}`;
try {
require(configRequirePath)(config, serverConfig);
localConfigFile = path.basename(configRequirePath);
} catch (error) {
console.error(
`Unable to load and apply settings from ${configRequirePath}`
);
console.error(error);
}
};
if (argv.config) {
readConfig(argv.config);
} else if (fs.existsSync(defaultLocalConfigPath)) {
readConfig(defaultLocalConfigPath);
}
const profilerUrl = `http://${host}:${port}`;
if (argv.profile) {
// Needed because of a later working directory change.
argv.profile = path.resolve(argv.profile);
// Spin up a simple http server serving the profile file.
const profileServer = http.createServer((req, res) => {
res.setHeader('Access-Control-Allow-Origin', profilerUrl);
const fileStream = fs.createReadStream(argv.profile);
fileStream.pipe(res);
});
// Close the profile server on CTRL-C.
process.on('SIGINT', () => profileServer.close());
process.on('SIGTERM', () => profileServer.close());
// Delete "open" target (if any) in serverConfig.
if (
typeof serverConfig.open === 'object' &&
!Array.isArray(serverConfig.open) &&
serverConfig.open !== null
) {
delete serverConfig.open.target;
} else {
delete serverConfig.open;
}
// Save and delete "open" property from serverConfig so that
// webpack-dev-server doesn't open anything in tandem.
const openOptions = serverConfig.open;
delete serverConfig.open;
// Open on profile.
profileServer.listen(0, host, () => {
const profileFromUrl = `${profilerUrl}/from-url/${encodeURIComponent(
`http://${host}:${profileServer.address().port}/${encodeURIComponent(
path.basename(argv.profile)
)}`
)}`;
import('open').then((open) => open.default(profileFromUrl, openOptions));
});
}
process.chdir(__dirname); // Allow server.js to be run from anywhere.
const server = new WebpackDevServer(serverConfig, webpack(config));
server
.start()
.then(() => {
const barAscii =
'------------------------------------------------------------------------------------------';
console.log(barAscii);
console.log(`> Firefox Profiler is listening at: ${profilerUrl}\n`);
if (port === 4242) {
console.log(
'> You can change this default port with the environment variable FX_PROFILER_PORT.\n'
);
}
if (localConfigFile) {
console.log(
`> We used your local file "${localConfigFile}" to mutate webpack’s config values.`
);
} else {
console.log(stripIndent`
> You can customize the webpack dev server by creating a webpack.local-config.js
> file that exports a single function that mutates the config values:
> (webpackConfig, serverConfig) => void
`);
}
console.log(barAscii);
})
.catch((err) => console.log(err));