universo-platform-2d

Форк
0
442 строки · 12.7 Кб
1
import { join } from 'node:path';
2
import { fileURLToPath } from 'node:url';
3

4
import type { BUILD_CONFIG_TYPE } from '@affine/env/global';
5
import { PerfseePlugin } from '@perfsee/webpack';
6
import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
7
import { sentryWebpackPlugin } from '@sentry/webpack-plugin';
8
import { VanillaExtractPlugin } from '@vanilla-extract/webpack-plugin';
9
import CopyPlugin from 'copy-webpack-plugin';
10
import { compact } from 'lodash-es';
11
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
12
import TerserPlugin from 'terser-webpack-plugin';
13
import webpack from 'webpack';
14
import type { Configuration as DevServerConfiguration } from 'webpack-dev-server';
15

16
import { projectRoot } from '../config/cwd.cjs';
17
import type { BuildFlags } from '../config/index.js';
18
import { productionCacheGroups } from './cache-group.js';
19
import { WebpackS3Plugin } from './s3-plugin.js';
20

21
const IN_CI = !!process.env.CI;
22

23
export const rootPath = join(fileURLToPath(import.meta.url), '..', '..');
24
export const workspaceRoot = join(rootPath, '..', '..', '..');
25

26
const OptimizeOptionOptions: (
27
  buildFlags: BuildFlags
28
) => webpack.Configuration['optimization'] = buildFlags => ({
29
  minimize: buildFlags.mode === 'production',
30
  minimizer: [
31
    new TerserPlugin({
32
      minify: TerserPlugin.swcMinify,
33
      exclude: [/plugins\/.+\/.+\.js$/, /plugins\/.+\/.+\.mjs$/],
34
      parallel: true,
35
      extractComments: true,
36
      terserOptions: {
37
        ecma: 2020,
38
        compress: {
39
          unused: true,
40
        },
41
        mangle: true,
42
      },
43
    }),
44
  ],
45
  removeEmptyChunks: true,
46
  providedExports: true,
47
  usedExports: true,
48
  sideEffects: true,
49
  removeAvailableModules: true,
50
  runtimeChunk: {
51
    name: 'runtime',
52
  },
53
  splitChunks: {
54
    chunks: 'all',
55
    minSize: 1,
56
    minChunks: 1,
57
    maxInitialRequests: Number.MAX_SAFE_INTEGER,
58
    maxAsyncRequests: Number.MAX_SAFE_INTEGER,
59
    cacheGroups: productionCacheGroups,
60
  },
61
});
62

63
export const getPublicPath = (buildFlags: BuildFlags) => {
64
  const { BUILD_TYPE } = process.env;
65
  if (typeof process.env.PUBLIC_PATH === 'string') {
66
    return process.env.PUBLIC_PATH;
67
  }
68

69
  if (
70
    buildFlags.mode === 'development' ||
71
    process.env.COVERAGE ||
72
    buildFlags.distribution === 'desktop'
73
  ) {
74
    return '/';
75
  }
76

77
  switch (BUILD_TYPE) {
78
    case 'stable':
79
      return 'https://prod.affineassets.com/';
80
    case 'beta':
81
      return 'https://beta.affineassets.com/';
82
    default:
83
      return 'https://dev.affineassets.com/';
84
  }
85
};
86

87
export const createConfiguration: (
88
  cwd: string,
89
  buildFlags: BuildFlags,
90
  buildConfig: BUILD_CONFIG_TYPE
91
) => webpack.Configuration = (cwd, buildFlags, buildConfig) => {
92
  const config = {
93
    name: 'affine',
94
    // to set a correct base path for the source map
95
    context: cwd,
96
    experiments: {
97
      topLevelAwait: true,
98
      outputModule: false,
99
      syncWebAssembly: true,
100
    },
101
    output: {
102
      environment: {
103
        module: true,
104
        dynamicImport: true,
105
      },
106
      filename:
107
        buildFlags.mode === 'production'
108
          ? 'js/[name].[contenthash:8].js'
109
          : 'js/[name].js',
110
      // In some cases webpack will emit files starts with "_" which is reserved in web extension.
111
      chunkFilename: pathData =>
112
        pathData.chunk?.name === 'worker'
113
          ? 'js/worker.[contenthash:8].js'
114
          : buildFlags.mode === 'production'
115
            ? 'js/chunk.[name].[contenthash:8].js'
116
            : 'js/chunk.[name].js',
117
      assetModuleFilename:
118
        buildFlags.mode === 'production'
119
          ? 'assets/[name].[contenthash:8][ext][query]'
120
          : '[name].[contenthash:8][ext]',
121
      devtoolModuleFilenameTemplate: 'webpack://[namespace]/[resource-path]',
122
      hotUpdateChunkFilename: 'hot/[id].[fullhash].js',
123
      hotUpdateMainFilename: 'hot/[runtime].[fullhash].json',
124
      path: join(cwd, 'dist'),
125
      clean: buildFlags.mode === 'production',
126
      globalObject: 'globalThis',
127
      // NOTE(@forehalo): always keep it '/'
128
      publicPath: '/',
129
      workerPublicPath: '/',
130
    },
131
    target: ['web', 'es2022'],
132

133
    mode: buildFlags.mode,
134

135
    devtool:
136
      buildFlags.mode === 'production'
137
        ? 'source-map'
138
        : 'eval-cheap-module-source-map',
139

140
    resolve: {
141
      symlinks: true,
142
      extensionAlias: {
143
        '.js': ['.js', '.tsx', '.ts'],
144
        '.mjs': ['.mjs', '.mts'],
145
      },
146
      extensions: ['.js', '.ts', '.tsx'],
147
      alias: {
148
        yjs: join(workspaceRoot, 'node_modules', 'yjs'),
149
        lit: join(workspaceRoot, 'node_modules', 'lit'),
150
      },
151
    },
152

153
    module: {
154
      parser: {
155
        javascript: {
156
          // Do not mock Node.js globals
157
          node: false,
158
          requireJs: false,
159
          import: true,
160
          // Treat as missing export as error
161
          strictExportPresence: true,
162
        },
163
      },
164
      rules: [
165
        {
166
          test: /\.m?js?$/,
167
          resolve: {
168
            fullySpecified: false,
169
          },
170
        },
171
        {
172
          test: /\.js$/,
173
          enforce: 'pre',
174
          include: /@blocksuite/,
175
          use: ['source-map-loader'],
176
        },
177
        {
178
          oneOf: [
179
            {
180
              test: /\.ts$/,
181
              exclude: /node_modules/,
182
              loader: 'swc-loader',
183
              options: {
184
                // https://swc.rs/docs/configuring-swc/
185
                jsc: {
186
                  preserveAllComments: true,
187
                  parser: {
188
                    syntax: 'typescript',
189
                    dynamicImport: true,
190
                    topLevelAwait: false,
191
                    tsx: false,
192
                    decorators: true,
193
                  },
194
                  target: 'es2022',
195
                  externalHelpers: false,
196
                  transform: {
197
                    useDefineForClassFields: false,
198
                    decoratorVersion: '2022-03',
199
                  },
200
                },
201
                sourceMaps: true,
202
                inlineSourcesContent: true,
203
              },
204
            },
205
            {
206
              test: /\.tsx$/,
207
              exclude: /node_modules/,
208
              loader: 'swc-loader',
209
              options: {
210
                // https://swc.rs/docs/configuring-swc/
211
                jsc: {
212
                  preserveAllComments: true,
213
                  parser: {
214
                    syntax: 'typescript',
215
                    dynamicImport: true,
216
                    topLevelAwait: false,
217
                    tsx: true,
218
                    decorators: true,
219
                  },
220
                  target: 'es2022',
221
                  externalHelpers: false,
222
                  transform: {
223
                    react: {
224
                      runtime: 'automatic',
225
                      refresh: buildFlags.mode === 'development' && {
226
                        refreshReg: '$RefreshReg$',
227
                        refreshSig: '$RefreshSig$',
228
                        emitFullSignatures: true,
229
                      },
230
                    },
231
                    useDefineForClassFields: false,
232
                    decoratorVersion: '2022-03',
233
                  },
234
                },
235
                sourceMaps: true,
236
                inlineSourcesContent: true,
237
              },
238
            },
239
            {
240
              test: /\.(png|jpg|gif|svg|webp|mp4|zip)$/,
241
              type: 'asset/resource',
242
            },
243
            {
244
              test: /\.(ttf|eot|woff|woff2)$/,
245
              type: 'asset/resource',
246
            },
247
            {
248
              test: /\.txt$/,
249
              type: 'asset/source',
250
            },
251
            {
252
              test: /\.inline\.svg$/,
253
              type: 'asset/inline',
254
            },
255
            {
256
              test: /\.css$/,
257
              use: [
258
                buildFlags.mode === 'development'
259
                  ? 'style-loader'
260
                  : MiniCssExtractPlugin.loader,
261
                {
262
                  loader: 'css-loader',
263
                  options: {
264
                    url: true,
265
                    sourceMap: false,
266
                    modules: false,
267
                    import: true,
268
                    importLoaders: 1,
269
                  },
270
                },
271
                {
272
                  loader: 'postcss-loader',
273
                  options: {
274
                    postcssOptions: {
275
                      config: join(rootPath, 'webpack', 'postcss.config.cjs'),
276
                    },
277
                  },
278
                },
279
              ],
280
            },
281
          ],
282
        },
283
      ],
284
    },
285
    plugins: compact([
286
      IN_CI ? null : new webpack.ProgressPlugin({ percentBy: 'entries' }),
287
      buildFlags.mode === 'development'
288
        ? new ReactRefreshWebpackPlugin({
289
            overlay: false,
290
            esModule: true,
291
            include: /\.tsx$/,
292
          })
293
        : // todo: support multiple entry points
294
          new MiniCssExtractPlugin({
295
            filename: `[name].[contenthash:8].css`,
296
            ignoreOrder: true,
297
          }),
298
      new VanillaExtractPlugin(),
299
      new webpack.DefinePlugin({
300
        'process.env.NODE_ENV': JSON.stringify(buildFlags.mode),
301
        'process.env.CAPTCHA_SITE_KEY': JSON.stringify(
302
          process.env.CAPTCHA_SITE_KEY
303
        ),
304
        'process.env.SENTRY_DSN': JSON.stringify(process.env.SENTRY_DSN),
305
        'process.env.BUILD_TYPE': JSON.stringify(process.env.BUILD_TYPE),
306
        'process.env.MIXPANEL_TOKEN': JSON.stringify(
307
          process.env.MIXPANEL_TOKEN
308
        ),
309
        'process.env.DEBUG_JOTAI': JSON.stringify(process.env.DEBUG_JOTAI),
310
        ...Object.entries(buildConfig).reduce(
311
          (def, [k, v]) => {
312
            def[`BUILD_CONFIG.${k}`] = JSON.stringify(v);
313
            return def;
314
          },
315
          {} as Record<string, string>
316
        ),
317
      }),
318
      buildFlags.distribution === 'admin'
319
        ? null
320
        : new CopyPlugin({
321
            patterns: [
322
              {
323
                // copy the shared public assets into dist
324
                from: join(
325
                  workspaceRoot,
326
                  'packages',
327
                  'frontend',
328
                  'core',
329
                  'public'
330
                ),
331
                to: join(cwd, 'dist'),
332
              },
333
            ],
334
          }),
335
      buildFlags.mode === 'production' && process.env.R2_SECRET_ACCESS_KEY
336
        ? new WebpackS3Plugin()
337
        : null,
338
    ]),
339
    stats: {
340
      errorDetails: true,
341
    },
342

343
    optimization: OptimizeOptionOptions(buildFlags),
344

345
    devServer: {
346
      hot: buildFlags.static ? false : 'only',
347
      liveReload: !buildFlags.static,
348
      client: {
349
        overlay: process.env.DISABLE_DEV_OVERLAY === 'true' ? false : undefined,
350
      },
351
      historyApiFallback: true,
352
      static: [
353
        {
354
          directory: join(
355
            projectRoot,
356
            'packages',
357
            'frontend',
358
            'core',
359
            'public'
360
          ),
361
          publicPath: '/',
362
          watch: !buildFlags.static,
363
        },
364
        {
365
          directory: join(cwd, 'public'),
366
          publicPath: '/',
367
          watch: !buildFlags.static,
368
        },
369
      ],
370
      proxy: [
371
        {
372
          context: '/api/worker/',
373
          target: 'https://affine.fail',
374
          changeOrigin: true,
375
          secure: false,
376
        },
377
        { context: '/api', target: 'http://localhost:3010' },
378
        { context: '/socket.io', target: 'http://localhost:3010', ws: true },
379
        { context: '/graphql', target: 'http://localhost:3010' },
380
      ],
381
    } as DevServerConfiguration,
382
  } satisfies webpack.Configuration;
383

384
  if (buildFlags.mode === 'production' && process.env.PERFSEE_TOKEN) {
385
    config.plugins.push(
386
      new PerfseePlugin({
387
        project: 'affine-toeverything',
388
      })
389
    );
390
  }
391

392
  if (buildFlags.mode === 'development') {
393
    config.optimization = {
394
      ...config.optimization,
395
      minimize: false,
396
      runtimeChunk: false,
397
      splitChunks: {
398
        maxInitialRequests: Infinity,
399
        chunks: 'all',
400
        cacheGroups: {
401
          errorHandler: {
402
            test: /global-error-handler/,
403
            priority: 1000,
404
            enforce: true,
405
          },
406
          defaultVendors: {
407
            test: `[\\/]node_modules[\\/](?!.*vanilla-extract)`,
408
            priority: -10,
409
            reuseExistingChunk: true,
410
          },
411
          default: {
412
            minChunks: 2,
413
            priority: -20,
414
            reuseExistingChunk: true,
415
          },
416
          styles: {
417
            name: 'styles',
418
            type: 'css/mini-extract',
419
            chunks: 'all',
420
            enforce: true,
421
          },
422
        },
423
      },
424
    };
425
  }
426

427
  if (
428
    process.env.SENTRY_AUTH_TOKEN &&
429
    process.env.SENTRY_ORG &&
430
    process.env.SENTRY_PROJECT
431
  ) {
432
    config.plugins.push(
433
      sentryWebpackPlugin({
434
        org: process.env.SENTRY_ORG,
435
        project: process.env.SENTRY_PROJECT,
436
        authToken: process.env.SENTRY_AUTH_TOKEN,
437
      })
438
    );
439
  }
440

441
  return config;
442
};
443

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.