5.7 KB178 lines
Blame
1/**
2 * Copyright (c) Meta Platforms, Inc. and affiliates.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 */
7
8import type {Plugin, PluginOption} from 'vite';
9
10import react from '@vitejs/plugin-react';
11import fs, {existsSync} from 'node:fs';
12import path from 'node:path';
13import {defineConfig} from 'vite';
14import styleX from 'vite-plugin-stylex';
15import viteTsconfigPaths from 'vite-tsconfig-paths';
16
17// Normalize `c:\foo\index.html` to `c:/foo/index.html`.
18// This affects Rollup's `facadeModuleId` (which expects the `c:/foo/bar` format),
19// and is important for Vite to replace the script tags in HTML files.
20// See https://github.com/vitejs/vite/blob/7440191715b07a50992fcf8c90d07600dffc375e/packages/vite/src/node/plugins/html.ts#L804
21// Without this, building on Windows might produce HTML entry points with
22// missing `<script>` tags, resulting in a blank page.
23function normalizeInputPath(inputPath: string) {
24 return process.platform === 'win32' ? path.resolve(inputPath).replace(/\\/g, '/') : inputPath;
25}
26
27const isInternal = existsSync(path.resolve(__dirname, 'facebook/README.facebook.md'));
28
29const input = [normalizeInputPath('webview.html')];
30if (isInternal) {
31 // Currently, the inline comment webview is not used in OSS
32 input.push(normalizeInputPath('inlineCommentWebview.html'));
33 input.push(normalizeInputPath('DiffCommentPanelWebview.html'));
34 input.push(normalizeInputPath('InlineCommentPanelWebview.html'));
35}
36
37console.log(isInternal ? 'Building internal version' : 'Building OSS version');
38
39// vite-plugin-stylex doesn't support renaming the output CSS file, so we have to do that ourselves.
40function moveStylexFilenamePlugin(): Plugin {
41 return {
42 name: 'move-stylex-filename',
43 writeBundle(options, bundle) {
44 for (const name in bundle) {
45 const chunk = bundle[name];
46 // Check if this is the stylex output cssfile
47 if (chunk.type === 'asset' && /assets[/\\]stylex\.[a-f0-9]+\.css/.test(chunk.fileName)) {
48 // Rename the file, move it from "assets" to "res" where the rest of our assets are
49 const newName = 'res/stylex.css';
50 if (options.dir == null) {
51 this.error('Could not replace StyleX output, dir must be set');
52 }
53 const dir = options.dir as string;
54 const oldPath = path.resolve(dir, chunk.fileName);
55 const newPath = path.resolve(dir, newName);
56 this.info(`Replacing StyleX output file ${chunk.fileName} with ${newName}`);
57 fs.renameSync(oldPath, newPath);
58 // Update the bundle object
59 chunk.fileName = newName;
60 bundle[newName] = chunk;
61 delete bundle[name];
62 }
63 }
64 },
65 };
66}
67
68const replaceFiles = (
69 replacements?: Array<{
70 file: string;
71 replacement: string;
72 }>,
73): PluginOption => {
74 const projectRoot = process.cwd();
75 replacements = replacements?.map(x => ({
76 file: path.join(projectRoot, x.file),
77 replacement: path.join(projectRoot, x.replacement),
78 }));
79
80 return {
81 name: 'vite-plugin-replace-files',
82 enforce: 'pre',
83 async resolveId(source: string, importer: string | undefined, options: any) {
84 const resolvedFile = await this.resolve(source, importer, {
85 ...options,
86 ...{skipSelf: true},
87 });
88
89 const foundReplacementFile = replacements?.find(
90 replacement => replacement.file == resolvedFile?.id,
91 );
92
93 if (foundReplacementFile) {
94 return {
95 id: foundReplacementFile.replacement,
96 };
97 }
98 return null;
99 },
100 };
101};
102
103export default defineConfig(({mode}) => ({
104 base: '',
105 plugins: [
106 replaceFiles([
107 {
108 file: '../isl/src/platform.ts',
109 replacement: './webview/vscodeWebviewPlatform.tsx',
110 },
111 ]),
112 react({
113 babel: {
114 plugins: [
115 [
116 'jotai/babel/plugin-debug-label',
117 {
118 customAtomNames: [
119 'atomFamilyWeak',
120 'atomLoadableWithRefresh',
121 'atomWithOnChange',
122 'atomWithRefresh',
123 'configBackedAtom',
124 'jotaiAtom',
125 'lazyAtom',
126 'localStorageBackedAtom',
127 ],
128 },
129 ],
130 ],
131 },
132 }),
133 styleX(),
134 viteTsconfigPaths(),
135 moveStylexFilenamePlugin(),
136 ],
137 build: {
138 outDir: 'dist/webview',
139 manifest: true,
140 // FIXME: This means that all webviews will use the same css file.
141 // This is too bloated for the inline comment webview and marginally slows down startup time.
142 // Ideally, we'd load all the relevant css files in the webview, but our current approach
143 // with our own manual copy of html in htmlForWebview does not support this.
144 cssCodeSplit: false,
145 rollupOptions: {
146 input,
147 output: {
148 // Don't use hashed names, so ISL webview panel can pre-define what filename to load
149 entryFileNames: '[name].js',
150 chunkFileNames: '[name].js',
151 assetFileNames: 'res/[name].[ext]',
152 },
153 },
154 copyPublicDir: true,
155 // No need for source maps in production. We can always build them locally to understand a wild stack trace.
156 sourcemap: mode === 'development',
157 },
158 worker: {
159 rollupOptions: {
160 output: {
161 // Don't use hashed names, so ISL webview panel can pre-define what filename to load
162 entryFileNames: 'worker/[name].js',
163 chunkFileNames: 'worker/[name].js',
164 assetFileNames: 'worker/[name].[ext]',
165 },
166 },
167 },
168 publicDir: '../isl/public',
169 server: {
170 // No need to open the browser, we run inside vscode and don't really connect to the server.
171 open: false,
172 port: 3015,
173 cors: {
174 origin: /^vscode-webview:\/\/.*/,
175 },
176 },
177}));
178