-
-
Notifications
You must be signed in to change notification settings - Fork 17
/
compiler.ts
executable file
·127 lines (117 loc) · 4.73 KB
/
compiler.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
import type { Context } from '@remix-run/dev/dist/compiler/context.js';
import { emptyModulesPlugin } from '@remix-run/dev/dist/compiler/plugins/emptyModules.js';
import { ServerMode } from '@remix-run/dev/dist/config/serverModes.js';
import { redBright, whiteBright } from 'colorette';
import type { BuildOptions, Plugin } from 'esbuild';
import esbuild from 'esbuild';
import path from 'node:path';
import assetsPlugin from './plugins/assets-module.js';
import entryModulePlugin from './plugins/entry-module.js';
import routesModulesPlugin from './plugins/routes-module.js';
import sideEffectsPlugin from './plugins/side-effects.js';
import type { ResolvedWorkerConfig } from './utils/config.js';
import readConfig from './utils/config.js';
import { watcher } from './utils/watcher.js';
const TIME_LABEL = '💿 Built Service Worker in';
/**
* Creates the esbuild config object.
*/
function createEsbuildConfig(config: ResolvedWorkerConfig): BuildOptions {
const pluginContext = { config } as unknown as Context;
return {
absWorkingDir: config.rootDirectory,
entryPoints: {
[config.workerName]: config.worker,
},
outdir: config.workerBuildDirectory,
platform: 'browser',
format: 'esm',
bundle: true,
define: {
'process.env.NODE_ENV': process.env.NODE_ENV === 'production' ? '"production"' : '"development"',
},
logLevel: 'error',
splitting: true,
sourcemap: config.workerSourcemap,
// As pointed out by https://github.com/evanw/esbuild/issues/2440, when tsconfig is set to
// `undefined`, esbuild will keep looking for a tsconfig.json recursively up. This unwanted
// behavior can only be avoided by creating an empty tsconfig file in the root directory.
// tsconfig: ctx.config.tsconfigPath,
mainFields: ['browser', 'module', 'main'],
treeShaking: true,
minify: config.workerMinify,
chunkNames: '_shared/sw/[name]-[hash]',
plugins: [
emptyModulesPlugin(pluginContext, /\.server(\.[jt]sx?)?$/) as Plugin,
// assuming that we dont need react at all in the worker (we dont want to SWSR for now at least)
emptyModulesPlugin(pluginContext, /^react(-dom)?(\/.*)?$/, {
includeNodeModules: true,
}) as Plugin,
emptyModulesPlugin(pluginContext, /^@remix-run\/(deno|cloudflare|node|react)(\/.*)?$/, {
includeNodeModules: true,
}) as Plugin,
// This plugin will generate a list of routes based on the remix `flatRoutes` output and inject them in the bundled `service-worker`.
entryModulePlugin(config),
// for each route imported with`?worker` suffix this plugin will only keep the `workerAction` and `workerLoader` exports
routesModulesPlugin(config),
// we need to generate a list of all the assets generated by the client bundle.
assetsPlugin(config),
// we need to tag the user entry.worker as sideEffect so esbuild will not remove it
sideEffectsPlugin(config),
],
supported: {
'import-meta': true,
},
};
}
export async function runCompiler(mode: 'dev' | 'build', projectDir: string = process.cwd()) {
const MODE = mode === 'dev' ? ServerMode.Development : ServerMode.Production;
readConfig(path.resolve(projectDir), MODE).then(remixConfig => {
console.time(TIME_LABEL);
if (mode === 'build') {
if (process.env.NODE_ENV === 'production') {
console.log(
redBright('⚠️ Oops! You are running Remix in development mode.'),
whiteBright('Overriding environment mode to production.')
);
}
process.env.NODE_ENV = 'production';
}
esbuild
.context({
...createEsbuildConfig(remixConfig),
metafile: true,
write: true,
color: true,
})
.then(async context => {
console.log(whiteBright(`🏗️ Building Service Worker in ${MODE} mode...\n`));
try {
if (mode === 'build') {
await context.rebuild();
console.timeEnd(TIME_LABEL);
console.log('🎉 Service Worker built successfully!');
return await context.dispose();
}
if (process.env.NODE_ENV === 'production') {
console.log(
redBright(
'⚠️ You are running Remix in production mode. This would be a good time to build your service worker.'
)
);
}
process.env.NODE_ENV = 'development';
await watcher(context, projectDir);
// await context.watch();
console.timeEnd(TIME_LABEL);
console.log('👀 Watching for changes in the service worker file...');
} catch (error) {
console.error(error);
}
})
.catch(error => {
console.error(error);
process.exit(1);
});
});
}