From cdef41220a060bc5a6aebc951fe758abcfce1579 Mon Sep 17 00:00:00 2001 From: Aleksandr Kitov Date: Tue, 15 Oct 2024 13:22:40 +0300 Subject: [PATCH] refactor(swc): change useSwcLoader option to codeLoader --- .changeset/three-camels-repeat.md | 13 +- packages/arui-scripts/docs/settings.md | 43 ++-- packages/arui-scripts/package.json | 2 +- .../arui-scripts/src/commands/build/client.ts | 1 - .../arui-scripts/src/commands/build/server.ts | 3 +- .../app-configs/calculate-dependent-config.ts | 4 +- .../src/configs/app-configs/get-defaults.ts | 4 +- .../src/configs/app-configs/types.ts | 10 +- .../app-configs/warn-about-deprecations.ts | 11 +- .../arui-scripts/src/configs/jest/settings.js | 60 +++-- .../src/configs/webpack.client.ts | 236 ++++++++++-------- .../src/configs/webpack.server.ts | 162 +++++++----- .../example-modules/arui-scripts.config.ts | 4 +- packages/example/arui-scripts.config.ts | 4 +- yarn.lock | 100 ++++---- 15 files changed, 368 insertions(+), 289 deletions(-) diff --git a/.changeset/three-camels-repeat.md b/.changeset/three-camels-repeat.md index d2956b79..7e15bd88 100644 --- a/.changeset/three-camels-repeat.md +++ b/.changeset/three-camels-repeat.md @@ -2,8 +2,17 @@ 'arui-scripts': minor --- -Добавлены флаги `useSwcLoader` для использования swc-loader и `jestUseSwc` для использования @swc/jest. +Добавляем возможность использовать swc для загрузки кода в webpack и jest. +- Добавлена настройка `codeLoader` для выбора используемого загрузчика кода. +Настройка заменяет собой уже существовавшую `useTscLoader` и добавляет возможность использовать в качестве +загрузчика swc. Использование swc значительно ускоряет сборку (до 2 раз), без особых негативных последствий. -Для большинства проектов миграция на swc будет абсолютно незаметна +- Добавлена настройка `jestCodeTransformer` для выбора обработчика кода для jest. +Заменяет собой `jestUseTsJest` и добавляет возможность использовать `@swc/jest`. swc в jest немного меняет поведение при использовании +spyOn для esm модулей. + +- Флаг `useTscLoader` помечен как deprecated и будет удален в следующем мажорном релизе. Используйте `codeLoader: 'tsc'`. +- Флаг `jestUseTsJest` помечен как deprecated и будет удален в следующем мажорном релизе. Используйте `jestCodeTransformer: 'tsc'`. +- Флаг `webpack4Compatibility` помечен как deprecated и будет удален в следующем мажорном релизе. diff --git a/packages/arui-scripts/docs/settings.md b/packages/arui-scripts/docs/settings.md index 33be7d1e..efb4cad6 100644 --- a/packages/arui-scripts/docs/settings.md +++ b/packages/arui-scripts/docs/settings.md @@ -197,6 +197,8 @@ const settings = { - `/^thrift-services\/proptypes/` #### useTscLoader +**Deprecated** Используйте настройку [codeLoader](#codeloader) + Использовать ts-loader вместо babel-loader для обработки ts файлов. **Не рекомендуется к использованию**. babel-loader является предпочтительным инструментом сборки, его стоят заменять только если в вашем проекте используется неподдерживаемый им синтаксис: @@ -208,35 +210,44 @@ babel-loader является предпочтительным инструме Рекомендуется обновить код проекта до поддерживаемого синтаксиса и использовать babel-loader. +#### codeLoader +Позволяет выбрать какой инструмент использовать для обработки js и ts кода приложения. По умолчанию `babel`. + +Возможные значения: +- `babel` - для всего кода будет использоваться `babel-loader`; +- `tsc` - для ts кода будет использоваться `ts-loader`, для всего остального - `babel-loader`; +- `swc` - для всего кода будет использоваться `swc-loader`. + +`swc` является предпочтительным режимом, дефолты не меняются для сохранения обратной совместимости. +Использование swc позволяет значительно ускорить сборку (до 2 раз на больших проектах), но не будет создавать полностью идентичный с babel код. +Итоговый бандл может получиться немного больше, чем при использовании babel, но разница полностью компенсируется при использовании сжатия. + #### webpack4Compatibility +**Deprecated** Эта настройка будет удалена в будущих версиях скриптов + Включить ли режим совместимости с webpack 4. По умолчанию `false`. Подробнее можно почитать в этом [issue](https://github.com/webpack/webpack/issues/14580). #### installServerSourceMaps Добавлять ли в серверную сборку пакет source-map-support. По умолчанию `false`. #### jestUseTsJest +**Deprecated** Используйте настройку [jestCodeTransformer](#jestcodetransformer) + Позволяет использовать `ts-jest` вместо `babel-jest` для обработки `ts` файлов при запуске тестов. По умолчанию `false`. +#### jestCodeTransformer +Позволяет выбрать какой инструмент использовать для обработки js и ts кода приложения при запуске тестов. По умолчанию `babel`. + +Возможные значения: +- `babel` - для всего кода будет использоваться `babel-jest`; +- `tsc` - для ts кода будет использоваться `ts-jest`, для всего остального - `babel-jest`; +- `swc` - для всего кода будет использоваться `@swc/jest`. + Swc более строго следует спецификациям и [не дает возможности](https://github.com/swc-project/swc/issues/5059) делать `spyOn` для экспортов из esm модулей. + #### collectCoverage Добавлять ли инструменты для сборки coverage при сборке. По умолчанию определяется по env переменным - будет выставлено в `true` если `NODE_ENV = 'cypress'` или `USE_ISTANBUL = 'enabled'`. Сбор coverage не будет работать при использовании `useTscLoader=true`. -#### useSwcLoader -Использовать ли swc для обработки js и ts файлов. По умолчанию `false`. - -Использование swc позволяет значительно ускорить сборку (до 2 раз на больших проектах), но не будет создавать полностью идентичный с babel код. -Итоговый может получиться немного больше, чем при использовании babel, но разница полностью компенсируется при использовании сжатия. - -При включении, swc будет использоваться вместо babel-loader при сборке, а так же для транспиляции файлов в jest. -Настройки `useTscLoader` и `jestUseTsJest` имеют приоритет над этой настройкой. - -#### jestUseSwc -Позволяет использовать `@swc/jest` вместо `babel-jest` для обработки `ts`/`js` файлов при запуске тестов. По умолчанию `false`. - -Аналогично использованию swc в сборке - значительно ускоряет запуск тестов. - -swc более строго следует спецификациям и [не дает возможности](https://github.com/swc-project/swc/issues/5059) делать `spyOn` для экспортов из esm модулей. - ### Обработка изображений #### dataUrlMaxSize Ресурсы, не превышающие данный размер (в байтах), будут включены в исходники `inline`, иначе вынесены в отдельный файл. По умолчанию `1536`. diff --git a/packages/arui-scripts/package.json b/packages/arui-scripts/package.json index 611e403e..f6cf8c3a 100644 --- a/packages/arui-scripts/package.json +++ b/packages/arui-scripts/package.json @@ -38,7 +38,7 @@ "@babel/runtime": "^7.23.8", "@csstools/postcss-global-data": "^2.0.1", "@pmmmwh/react-refresh-webpack-plugin": "0.5.11", - "@swc/core": "~1.6.13", + "@swc/core": "^1.7.35", "@swc/jest": "^0.2.36", "assets-webpack-plugin": "7.1.1", "autoprefixer": "^10.3.16", diff --git a/packages/arui-scripts/src/commands/build/client.ts b/packages/arui-scripts/src/commands/build/client.ts index 0624fb91..38fd5679 100644 --- a/packages/arui-scripts/src/commands/build/client.ts +++ b/packages/arui-scripts/src/commands/build/client.ts @@ -12,7 +12,6 @@ console.log(chalk.magenta('Building client...')); build(config) .then(({ stats, warnings }) => { - console.timeEnd('build client'); if (warnings.length) { console.log(chalk.yellow('Client compiled with warnings.\n')); console.log(warnings.join('\n\n')); diff --git a/packages/arui-scripts/src/commands/build/server.ts b/packages/arui-scripts/src/commands/build/server.ts index 601238cb..512ad175 100644 --- a/packages/arui-scripts/src/commands/build/server.ts +++ b/packages/arui-scripts/src/commands/build/server.ts @@ -7,10 +7,9 @@ import build from './build-wrapper'; import config from '../../configs/webpack.server.prod'; console.log(chalk.magenta('Building server...')); -console.time('build server'); + build(config as any) .then(({ warnings }) => { - console.timeEnd('build server'); if (warnings.length) { console.log(chalk.yellow('Server compiled with warnings.\n')); console.log(warnings.join('\n\n')); diff --git a/packages/arui-scripts/src/configs/app-configs/calculate-dependent-config.ts b/packages/arui-scripts/src/configs/app-configs/calculate-dependent-config.ts index a148b87c..007f7a79 100644 --- a/packages/arui-scripts/src/configs/app-configs/calculate-dependent-config.ts +++ b/packages/arui-scripts/src/configs/app-configs/calculate-dependent-config.ts @@ -10,9 +10,11 @@ import { AppConfigs, AppContext } from './types'; /** * Обновление ключей конфига, зависящих от других. Это нужно делать в самый последний момент */ -export function calculateDependentConfig(config: AppConfigs) { +export function calculateDependentConfig(config: AppConfigs): AppConfigs { return { ...config, + codeLoader: config.useTscLoader ? 'tsc' : config.codeLoader, + jestCodeTransformer: config.jestUseTsJest ? 'tsc' : config.jestCodeTransformer, clientPolyfillsEntry: getPolyfills(config), }; } diff --git a/packages/arui-scripts/src/configs/app-configs/get-defaults.ts b/packages/arui-scripts/src/configs/app-configs/get-defaults.ts index ba7ce97a..bbf3d634 100644 --- a/packages/arui-scripts/src/configs/app-configs/get-defaults.ts +++ b/packages/arui-scripts/src/configs/app-configs/get-defaults.ts @@ -47,12 +47,12 @@ export function getDefaultAppConfig(): AppConfigs { // build tuning keepPropTypes: false, useTscLoader: false, - useSwcLoader: false, + codeLoader: 'babel', webpack4Compatibility: false, installServerSourceMaps: false, disableDevWebpackTypecheck: true, jestUseTsJest: false, - jestUseSwc: false, + jestCodeTransformer: 'babel', collectCoverage: process.env.NODE_ENV === 'cypress' || process.env.USE_ISTANBUL === 'enabled', // image processing diff --git a/packages/arui-scripts/src/configs/app-configs/types.ts b/packages/arui-scripts/src/configs/app-configs/types.ts index 58090055..65541fc9 100644 --- a/packages/arui-scripts/src/configs/app-configs/types.ts +++ b/packages/arui-scripts/src/configs/app-configs/types.ts @@ -42,12 +42,18 @@ export type AppConfigs = { * @deprecated использование ts-loader крайне не рекомендуется - он медленнее и не имеет преимуществ перед babel */ useTscLoader: boolean; - useSwcLoader: boolean; + codeLoader: 'babel' | 'tsc' | 'swc'; + /** + * @deprecated эта настройка будет удалена в будущих версиях скриптов + */ webpack4Compatibility: boolean; installServerSourceMaps: boolean; disableDevWebpackTypecheck: boolean; + /** + * @deprecated используйте настройку jestCodeTransformer + */ jestUseTsJest: boolean; - jestUseSwc: boolean; + jestCodeTransformer: 'babel' | 'tsc' | 'swc'; collectCoverage: boolean; // image processing diff --git a/packages/arui-scripts/src/configs/app-configs/warn-about-deprecations.ts b/packages/arui-scripts/src/configs/app-configs/warn-about-deprecations.ts index 4d4b969c..91404817 100644 --- a/packages/arui-scripts/src/configs/app-configs/warn-about-deprecations.ts +++ b/packages/arui-scripts/src/configs/app-configs/warn-about-deprecations.ts @@ -9,11 +9,10 @@ export function warnAboutDeprecations(config: AppContextWithConfigs) { ); } - if (config.useSwcLoader && config.useTscLoader) { - console.warn('Одновременное использование опций `useSwcLoader` и `useTscLoader` не поддерживается, выберите что-то одно'); - } - - if (config.jestUseSwc && config.jestUseTsJest) { - console.warn('Одновременное использование опций `jestUseSwc` и `jestUseTsJest` не поддерживается, выберите что-то одно'); + if (config.webpack4Compatibility) { + console.warn( + 'Опция `webpack4Compatibility` будет удалена в будущих версиях arui-scripts.', + 'Обратитесь к issue в webpack https://github.com/webpack/webpack/issues/14580 для получения дополнительной информации', + ); } } diff --git a/packages/arui-scripts/src/configs/jest/settings.js b/packages/arui-scripts/src/configs/jest/settings.js index 77a577b1..e7ae6303 100644 --- a/packages/arui-scripts/src/configs/jest/settings.js +++ b/packages/arui-scripts/src/configs/jest/settings.js @@ -10,27 +10,6 @@ const { swcJestConfig } = require('../swc'); const configs = require('../app-configs').default; -let tsConfigPaths = {}; - -if (configs.tsconfig) { - const tsConfigText = fs.readFileSync(configs.tsconfig, 'utf8'); - const tsConfig = parseConfigFileTextToJson(configs.tsconfig, tsConfigText); - - tsConfigPaths = tsConfig.config.compilerOptions?.paths || {}; -} - -let tsxTransformer = require.resolve('./babel-transform'); -const jsTransformer = configs.jestUseSwc - ? [require.resolve('@swc/jest'), swcJestConfig] - : require.resolve('./babel-transform'); - -if (configs.jestUseSwc) { - tsxTransformer = [require.resolve('@swc/jest'), swcJestConfig]; -} -if (configs.jestUseTsJest) { - tsxTransformer = require.resolve('ts-jest'); -} - module.exports = { testRegex: 'src/.*(((/__test__/|/__tests__/).*)|(test|spec|tests)).(jsx?|tsx?)$', moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'], @@ -39,15 +18,15 @@ module.exports = { url: 'http://localhost', }, transform: { - '^.+\\.jsx?$': jsTransformer, - '^.+\\.mjs$': jsTransformer, - '^.+\\.tsx?$': tsxTransformer, + '^.+\\.jsx?$': getJsTransformer(), + '^.+\\.mjs$': getJsTransformer(), + '^.+\\.tsx?$': getTsTransformer(), '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': require.resolve('./file-transform'), }, moduleNameMapper: { // replace all css files with simple empty exports '\\.css$': require.resolve('./css-mock'), - ...pathsToModuleNameMapper(tsConfigPaths, { prefix: '/' }), + ...pathsToModuleNameMapper(getPathMapping(), { prefix: '/' }), }, snapshotSerializers: [require.resolve('jest-snapshot-serializer-class-name-to-string')], globals: { @@ -56,3 +35,34 @@ module.exports = { }, }, }; + +function getPathMapping() { + if (!configs.tsconfig) { + return {}; + } + + const tsConfigText = fs.readFileSync(configs.tsconfig, 'utf8'); + const tsConfig = parseConfigFileTextToJson(configs.tsconfig, tsConfigText); + + return tsConfig.config.compilerOptions?.paths || {}; +} + +function getTsTransformer() { + if (configs.jestCodeTransformer === 'tsc') { + return require.resolve('ts-jest'); + } + + if (configs.jestCodeTransformer === 'swc') { + return [require.resolve('@swc/jest'), swcJestConfig]; + } + + return require.resolve('./babel-transform') +} + +function getJsTransformer() { + if (configs.jestCodeTransformer === 'swc') { + return [require.resolve('@swc/jest'), swcJestConfig]; + } + + return require.resolve('./babel-transform'); +} diff --git a/packages/arui-scripts/src/configs/webpack.client.ts b/packages/arui-scripts/src/configs/webpack.client.ts index 0e1db494..56e5d9d3 100644 --- a/packages/arui-scripts/src/configs/webpack.client.ts +++ b/packages/arui-scripts/src/configs/webpack.client.ts @@ -259,113 +259,12 @@ export const createSingleClientWebpackConfig = ( // match the requirements. When no loader matches it will fall // back to the "file" loader at the end of the loader list. oneOf: [ - // Process JS with Babel. - { - test: configs.useTscLoader - ? /\.(js|jsx|mjs|cjs)$/ - : /\.(js|jsx|mjs|ts|tsx|cjs)$/, - include: configs.appSrc, - ...(configs.useSwcLoader - ? { - loader: require.resolve('swc-loader'), - options: { - cacheDirectory: mode === 'dev', - cacheCompression: false, - ...swcClientConfig, - jsc: { - ...swcClientConfig.jsc, - transform: { - ...swcClientConfig.jsc?.transform, - react: { - ...swcClientConfig.jsc?.transform?.react, - refresh: mode === 'dev', - }, - }, - }, - }, - } - : { - loader: require.resolve('babel-loader'), - options: { - ...babelConf, - cacheDirectory: mode === 'dev', - cacheCompression: false, - plugins: [ - ...babelConf.plugins, - mode === 'dev' - ? [ - require.resolve('react-refresh/babel'), - { skipEnvCheck: true }, - ] - : undefined, - ].filter(Boolean), - }, - } - ), - }, - configs.tsconfig && - configs.useTscLoader && { - test: /\.tsx?$/, - use: [ - { - loader: require.resolve('babel-loader'), - options: { - ...babelConf, - cacheDirectory: mode === 'dev', - cacheCompression: false, - plugins: - mode === 'dev' - ? [ - require.resolve('react-refresh/babel'), - { skipEnvCheck: true }, - ] - : undefined, - }, - }, - { - loader: require.resolve('ts-loader'), - options: { - getCustomTransformers: () => ({ - before: - mode === 'dev' ? [ReactRefreshTypeScript()] : [], - }), - onlyCompileBundledFiles: true, - transpileOnly: true, - happyPackMode: true, - configFile: configs.tsconfig, - }, - }, - ], - }, - // Process any JS outside of the app with Babel. - // Unlike the application JS, we only compile the standard ES features. - { - test: /\.(js|mjs)$/, - exclude: /@babel(?:\/|\\{1,2})runtime/, - resolve: { - fullySpecified: false, - }, - ...(configs.useSwcLoader - ? { - loader: require.resolve('swc-loader'), - options: { - cacheDirectory: mode === 'dev', - cacheCompression: false, - }, - } - : { - loader: require.resolve('babel-loader'), - options: { - ...babelDependencies, - babelrc: false, - configFile: false, - compact: false, - cacheDirectory: mode === 'dev', - cacheCompression: false, - }, - } - ), - }, + // Обработка основного кода приложения + getCodeLoader(mode), + // обработка ts кода если codeLoader = tsc + getTsLoaderIfEnabled(mode), + // Обработка внешнего для приложения кода (node_modules) + getExternalCodeLoader(mode), // process simple css files with postcss loader and css loader { test: /\.css$/, @@ -479,7 +378,7 @@ export const createSingleClientWebpackConfig = ( ), (mode === 'prod' || !configs.disableDevWebpackTypecheck) && configs.tsconfig !== null && - !configs.useTscLoader && + configs.codeLoader !== 'tsc' && new ForkTsCheckerWebpackPlugin(), // moment.js очень большая библиотека, которая включает в себя массу локализаций, которые мы не используем. // Поэтому мы их просто игнорируем, чтобы не включать в сборку. @@ -595,3 +494,124 @@ export const createClientWebpackConfig = (mode: 'dev' | 'prod') => { return [appWebpackConfig, ...modulesWebpackConfigs]; }; + +function getCodeLoader(mode: 'dev' | 'prod'): webpack.RuleSetRule { + if (configs.codeLoader === 'swc') { + return { + test: /\.(js|jsx|mjs|ts|tsx|cjs)$/, + include: configs.appSrc, + loader: require.resolve('swc-loader'), + options: { + cacheDirectory: mode === 'dev', + cacheCompression: false, + ...swcClientConfig, + jsc: { + ...swcClientConfig.jsc, + transform: { + ...swcClientConfig.jsc?.transform, + react: { + ...swcClientConfig.jsc?.transform?.react, + refresh: mode === 'dev', + }, + }, + }, + }, + }; + } + + return { + test: configs.codeLoader === 'tsc' + ? /\.(js|jsx|mjs|cjs)$/ + : /\.(js|jsx|mjs|ts|tsx|cjs)$/, + include: configs.appSrc, + loader: require.resolve('babel-loader'), + options: { + ...babelConf, + cacheDirectory: mode === 'dev', + cacheCompression: false, + plugins: [ + ...babelConf.plugins, + mode === 'dev' + ? [ + require.resolve('react-refresh/babel'), + { skipEnvCheck: true }, + ] + : undefined, + ].filter(Boolean), + }, + }; +} + +function getTsLoaderIfEnabled(mode: 'dev' | 'prod'): webpack.RuleSetRule | false { + if (configs.codeLoader !== 'tsc' || !configs.tsconfig) { + return false; + } + + return { + test: /\.tsx?$/, + use: [ + { + loader: require.resolve('babel-loader'), + options: { + ...babelConf, + cacheDirectory: mode === 'dev', + cacheCompression: false, + plugins: + mode === 'dev' + ? [ + require.resolve('react-refresh/babel'), + { skipEnvCheck: true }, + ] + : undefined, + }, + }, + { + loader: require.resolve('ts-loader'), + options: { + getCustomTransformers: () => ({ + before: + mode === 'dev' ? [ReactRefreshTypeScript()] : [], + }), + onlyCompileBundledFiles: true, + transpileOnly: true, + happyPackMode: true, + configFile: configs.tsconfig, + }, + }, + ], + } +} + +function getExternalCodeLoader(mode: 'dev' | 'prod'): webpack.RuleSetRule { + const baseLoaderConfig = { + test: /\.(js|mjs)$/, + exclude: /@babel(?:\/|\\{1,2})runtime/, + resolve: { + fullySpecified: false, + }, + }; + + if (configs.codeLoader === 'swc') { + return { + ...baseLoaderConfig, + loader: require.resolve('swc-loader'), + options: { + cacheDirectory: mode === 'dev', + cacheCompression: false, + }, + }; + } + + return { + ...baseLoaderConfig, + loader: require.resolve('babel-loader'), + options: { + ...babelDependencies, + babelrc: false, + configFile: false, + compact: false, + cacheDirectory: mode === 'dev', + cacheCompression: false, + }, + }; +} diff --git a/packages/arui-scripts/src/configs/webpack.server.ts b/packages/arui-scripts/src/configs/webpack.server.ts index 8f0a4be8..3fd34299 100644 --- a/packages/arui-scripts/src/configs/webpack.server.ts +++ b/packages/arui-scripts/src/configs/webpack.server.ts @@ -127,75 +127,12 @@ export const createServerConfig = (mode: 'dev' | 'prod'): Configuration => ({ rules: [ { oneOf: [ - // Process JS with Babel. - { - test: configs.useTscLoader ? /\.(js|jsx|mjs)$/ : /\.(js|jsx|mjs|ts|tsx)$/, - include: configs.appSrc, - ...(configs.useSwcLoader - ? { - loader: require.resolve('swc-loader'), - options: swcServerConfig, - } - : { - loader: require.resolve('babel-loader'), - options: { - ...babelConf, - // This is a feature of `babel-loader` for webpack (not Babel itself). - // It enables caching results in ./node_modules/.cache/babel-loader/ - // directory for faster rebuilds. - cacheDirectory: mode === 'dev', - }, - }), - }, - configs.tsconfig && - configs.useTscLoader && { - test: /\.tsx?$/, - use: [ - { - loader: require.resolve('babel-loader'), - options: { - // This is a feature of `babel-loader` for webpack (not Babel itself). - // It enables caching results in ./node_modules/.cache/babel-loader/ - // directory for faster rebuilds. - cacheDirectory: mode === 'dev', - ...babelConf, - }, - }, - { - loader: require.resolve('ts-loader'), - options: { - onlyCompileBundledFiles: true, - transpileOnly: true, - happyPackMode: true, - configFile: configs.tsconfig, - }, - }, - ], - }, - // Process any JS outside of the app with Babel. - // Unlike the application JS, we only compile the standard ES features. - { - test: /\.(js|mjs)$/, - exclude: /@babel(?:\/|\\{1,2})runtime/, - resolve: { - fullySpecified: false, - }, - ...(configs.useSwcLoader - ? { - loader: require.resolve('swc-loader'), - } - : { - loader: require.resolve('babel-loader'), - options: { - ...babelDependencies, - babelrc: false, - configFile: false, - compact: false, - cacheDirectory: mode === 'dev', - cacheCompression: false, - }, - }), - }, + // Обработка основного кода приложения + getCodeLoader(mode), + // обработка ts кода если codeLoader = tsc + getTsLoaderIfEnabled(mode), + // Обработка внешнего для приложения кода (node_modules) + getExternalCodeLoader(mode), // replace css imports with empty files { test: cssRegex, @@ -283,3 +220,90 @@ export const createServerConfig = (mode: 'dev' | 'prod'): Configuration => ({ hints: false, }, }); + +function getCodeLoader(mode: 'dev' | 'prod'): webpack.RuleSetRule { + if (configs.codeLoader === 'swc') { + return { + test: /\.(js|jsx|mjs|ts|tsx|cjs)$/, + include: configs.appSrc, + loader: require.resolve('swc-loader'), + options: swcServerConfig, + }; + } + + return { + test: configs.codeLoader === 'tsc' + ? /\.(js|jsx|mjs|cjs)$/ + : /\.(js|jsx|mjs|ts|tsx|cjs)$/, + include: configs.appSrc, + loader: require.resolve('babel-loader'), + options: { + ...babelConf, + // This is a feature of `babel-loader` for webpack (not Babel itself). + // It enables caching results in ./node_modules/.cache/babel-loader/ + // directory for faster rebuilds. + cacheDirectory: mode === 'dev', + }, + }; +} + +function getTsLoaderIfEnabled(mode: 'dev' | 'prod'): webpack.RuleSetRule | false { + if (configs.codeLoader !== 'tsc' || !configs.tsconfig) { + return false; + } + + return { + test: /\.tsx?$/, + use: [ + { + loader: require.resolve('babel-loader'), + options: { + // This is a feature of `babel-loader` for webpack (not Babel itself). + // It enables caching results in ./node_modules/.cache/babel-loader/ + // directory for faster rebuilds. + cacheDirectory: mode === 'dev', + ...babelConf, + }, + }, + { + loader: require.resolve('ts-loader'), + options: { + onlyCompileBundledFiles: true, + transpileOnly: true, + happyPackMode: true, + configFile: configs.tsconfig, + }, + }, + ], + }; +} + +function getExternalCodeLoader(mode: 'dev' | 'prod'): webpack.RuleSetRule { + const baseLoaderConfig = { + test: /\.(js|mjs)$/, + exclude: /@babel(?:\/|\\{1,2})runtime/, + resolve: { + fullySpecified: false, + }, + }; + + if (configs.codeLoader === 'swc') { + return { + ...baseLoaderConfig, + loader: require.resolve('swc-loader'), + }; + } + + return { + ...baseLoaderConfig, + loader: require.resolve('babel-loader'), + options: { + ...babelDependencies, + babelrc: false, + configFile: false, + compact: false, + cacheDirectory: mode === 'dev', + cacheCompression: false, + }, + }; +} diff --git a/packages/example-modules/arui-scripts.config.ts b/packages/example-modules/arui-scripts.config.ts index 38471268..60429c78 100644 --- a/packages/example-modules/arui-scripts.config.ts +++ b/packages/example-modules/arui-scripts.config.ts @@ -10,8 +10,8 @@ const aruiScriptsConfig: PackageSettings = { clientEntry: './src/client', componentsTheme: '../../node_modules/@alfalab/core-components/themes/corp.css', keepCssVars: false, - useSwcLoader: true, - jestUseSwc: true, + codeLoader: 'swc', + jestCodeTransformer: 'swc', debug: true, compatModules: { shared: { diff --git a/packages/example/arui-scripts.config.ts b/packages/example/arui-scripts.config.ts index 3df0330b..39c18240 100644 --- a/packages/example/arui-scripts.config.ts +++ b/packages/example/arui-scripts.config.ts @@ -8,8 +8,8 @@ const aruiScriptsConfig: PackageSettings = { componentsTheme: '../../node_modules/@alfalab/core-components/themes/corp.css', keepCssVars: false, debug: true, - useSwcLoader: true, - jestUseSwc: true, + codeLoader: 'swc', + jestCodeTransformer: 'swc', compatModules: { shared: { 'react': 'react', diff --git a/yarn.lock b/yarn.lock index debbc428..c9a1c8fe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4154,92 +4154,92 @@ __metadata: languageName: node linkType: hard -"@swc/core-darwin-arm64@npm:1.6.13": - version: 1.6.13 - resolution: "@swc/core-darwin-arm64@npm:1.6.13" +"@swc/core-darwin-arm64@npm:1.7.35": + version: 1.7.35 + resolution: "@swc/core-darwin-arm64@npm:1.7.35" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@swc/core-darwin-x64@npm:1.6.13": - version: 1.6.13 - resolution: "@swc/core-darwin-x64@npm:1.6.13" +"@swc/core-darwin-x64@npm:1.7.35": + version: 1.7.35 + resolution: "@swc/core-darwin-x64@npm:1.7.35" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-arm-gnueabihf@npm:1.6.13": - version: 1.6.13 - resolution: "@swc/core-linux-arm-gnueabihf@npm:1.6.13" +"@swc/core-linux-arm-gnueabihf@npm:1.7.35": + version: 1.7.35 + resolution: "@swc/core-linux-arm-gnueabihf@npm:1.7.35" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@swc/core-linux-arm64-gnu@npm:1.6.13": - version: 1.6.13 - resolution: "@swc/core-linux-arm64-gnu@npm:1.6.13" +"@swc/core-linux-arm64-gnu@npm:1.7.35": + version: 1.7.35 + resolution: "@swc/core-linux-arm64-gnu@npm:1.7.35" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@swc/core-linux-arm64-musl@npm:1.6.13": - version: 1.6.13 - resolution: "@swc/core-linux-arm64-musl@npm:1.6.13" +"@swc/core-linux-arm64-musl@npm:1.7.35": + version: 1.7.35 + resolution: "@swc/core-linux-arm64-musl@npm:1.7.35" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@swc/core-linux-x64-gnu@npm:1.6.13": - version: 1.6.13 - resolution: "@swc/core-linux-x64-gnu@npm:1.6.13" +"@swc/core-linux-x64-gnu@npm:1.7.35": + version: 1.7.35 + resolution: "@swc/core-linux-x64-gnu@npm:1.7.35" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@swc/core-linux-x64-musl@npm:1.6.13": - version: 1.6.13 - resolution: "@swc/core-linux-x64-musl@npm:1.6.13" +"@swc/core-linux-x64-musl@npm:1.7.35": + version: 1.7.35 + resolution: "@swc/core-linux-x64-musl@npm:1.7.35" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@swc/core-win32-arm64-msvc@npm:1.6.13": - version: 1.6.13 - resolution: "@swc/core-win32-arm64-msvc@npm:1.6.13" +"@swc/core-win32-arm64-msvc@npm:1.7.35": + version: 1.7.35 + resolution: "@swc/core-win32-arm64-msvc@npm:1.7.35" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@swc/core-win32-ia32-msvc@npm:1.6.13": - version: 1.6.13 - resolution: "@swc/core-win32-ia32-msvc@npm:1.6.13" +"@swc/core-win32-ia32-msvc@npm:1.7.35": + version: 1.7.35 + resolution: "@swc/core-win32-ia32-msvc@npm:1.7.35" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@swc/core-win32-x64-msvc@npm:1.6.13": - version: 1.6.13 - resolution: "@swc/core-win32-x64-msvc@npm:1.6.13" +"@swc/core-win32-x64-msvc@npm:1.7.35": + version: 1.7.35 + resolution: "@swc/core-win32-x64-msvc@npm:1.7.35" conditions: os=win32 & cpu=x64 languageName: node linkType: hard -"@swc/core@npm:~1.6.13": - version: 1.6.13 - resolution: "@swc/core@npm:1.6.13" +"@swc/core@npm:^1.7.35": + version: 1.7.35 + resolution: "@swc/core@npm:1.7.35" dependencies: - "@swc/core-darwin-arm64": 1.6.13 - "@swc/core-darwin-x64": 1.6.13 - "@swc/core-linux-arm-gnueabihf": 1.6.13 - "@swc/core-linux-arm64-gnu": 1.6.13 - "@swc/core-linux-arm64-musl": 1.6.13 - "@swc/core-linux-x64-gnu": 1.6.13 - "@swc/core-linux-x64-musl": 1.6.13 - "@swc/core-win32-arm64-msvc": 1.6.13 - "@swc/core-win32-ia32-msvc": 1.6.13 - "@swc/core-win32-x64-msvc": 1.6.13 + "@swc/core-darwin-arm64": 1.7.35 + "@swc/core-darwin-x64": 1.7.35 + "@swc/core-linux-arm-gnueabihf": 1.7.35 + "@swc/core-linux-arm64-gnu": 1.7.35 + "@swc/core-linux-arm64-musl": 1.7.35 + "@swc/core-linux-x64-gnu": 1.7.35 + "@swc/core-linux-x64-musl": 1.7.35 + "@swc/core-win32-arm64-msvc": 1.7.35 + "@swc/core-win32-ia32-msvc": 1.7.35 + "@swc/core-win32-x64-msvc": 1.7.35 "@swc/counter": ^0.1.3 - "@swc/types": ^0.1.9 + "@swc/types": ^0.1.13 peerDependencies: "@swc/helpers": "*" dependenciesMeta: @@ -4266,7 +4266,7 @@ __metadata: peerDependenciesMeta: "@swc/helpers": optional: true - checksum: 4b2cddfac17e48ec5afc1942a6a39e9ea5af7fe15b4cebbc72f4569bffbea8ddf66ddf3055a931a6d79e713e3991a0ba9f0c764fc88175358084261dadffe277 + checksum: d3482664c500b55c2efbb3d171616451c6b8868dce1dab5c632c5156bc6f72938531ab898ad8e5b3067ac8a2f5702ae1a5aed1ff6d0abb93f6711d9665752e51 languageName: node linkType: hard @@ -4290,12 +4290,12 @@ __metadata: languageName: node linkType: hard -"@swc/types@npm:^0.1.9": - version: 0.1.12 - resolution: "@swc/types@npm:0.1.12" +"@swc/types@npm:^0.1.13": + version: 0.1.13 + resolution: "@swc/types@npm:0.1.13" dependencies: "@swc/counter": ^0.1.3 - checksum: cf7f89e46f859864075d7965582baea9c5f98830f45b1046251568c9bdf1ca484b1bf37f6d3c32b7c82ecf8cd5df89d22f05268c391819c44e49911bb1a8e71a + checksum: 4d9ef0fba20e410bee38b20b60eeb284a1284c1cf6b5f84754b6f5e467e5e0621e2db67dc31e22c524a8d63f36d0a1d530126cd97752a85f140d91bf53553e01 languageName: node linkType: hard @@ -6397,7 +6397,7 @@ __metadata: "@babel/runtime": ^7.23.8 "@csstools/postcss-global-data": ^2.0.1 "@pmmmwh/react-refresh-webpack-plugin": 0.5.11 - "@swc/core": ~1.6.13 + "@swc/core": ^1.7.35 "@swc/jest": ^0.2.36 "@types/assets-webpack-plugin": 6.1.2 "@types/case-sensitive-paths-webpack-plugin": 2.1.6