Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(*): add useSwc option #251

Merged
merged 4 commits into from
Oct 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions .changeset/three-camels-repeat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
'arui-scripts': minor
---

Добавляем возможность использовать swc для загрузки кода в webpack и jest.

- Добавлена настройка `codeLoader` для выбора используемого загрузчика кода.
Настройка заменяет собой уже существовавшую `useTscLoader` и добавляет возможность использовать в качестве
загрузчика swc.
Использование swc значительно ускоряет сборку (до 2 раз), без особых негативных последствий.

- Добавлена настройка `jestCodeTransformer` для выбора обработчика кода для jest.
Заменяет собой `jestUseTsJest` и добавляет возможность использовать `@swc/jest`. swc в jest немного меняет поведение при использовании
spyOn для esm модулей.

- Флаг `useTscLoader` помечен как deprecated и будет удален в следующем мажорном релизе. Используйте `codeLoader: 'tsc'`.
- Флаг `jestUseTsJest` помечен как deprecated и будет удален в следующем мажорном релизе. Используйте `jestCodeTransformer: 'tsc'`.
- Флаг `webpack4Compatibility` помечен как deprecated и будет удален в следующем мажорном релизе.
2 changes: 2 additions & 0 deletions packages/arui-scripts/.eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,7 @@ module.exports = {
'import/no-named-as-default': 'warn',
// чтобы могли использовать for и генераторы
'no-restricted-syntax': 'off',
// проект - cli-тулза, и она должна писать в консоль
'no-console': 'off',
},
};
3 changes: 3 additions & 0 deletions packages/arui-scripts/docs/overrides.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ export default overrides;
- `start.sh` - шаблон entrypoint докер контейнера. Базовый шаблон [тут](../src/templates/start.template.ts).
- `serverExternalsExemptions` - список модулей, которые не будут добавлены в список внешних зависимостей сервера. [Подробнее](caveats.md#node-externals).
- `html` - шаблон для htmlWebpackPlugin, будет использоваться только в режиме [`clientOnly`](./settings.md#clientonly).
- `swc-client` - конфигурация `swc` для клиентского кода. Ключи: `swc`, `swcClient`.
- `swc-server` - конфигурация `swc` для серверного кода. Ключи: `swc`, `swcServer`.
- `swc-jest` - конфигурация `swc` для тестов. Ключи: `swc`, `swcJest`.

Для некоторых конфигураций определены несколько ключей, они будут применяться в том порядке, в котором они приведены в этом файле.

Expand Down
27 changes: 27 additions & 0 deletions packages/arui-scripts/docs/settings.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ const settings = {
- `/^thrift-services\/proptypes/`

#### useTscLoader
**Deprecated** Используйте настройку [codeLoader](#codeloader)

Использовать ts-loader вместо babel-loader для обработки ts файлов. **Не рекомендуется к использованию**.

babel-loader является предпочтительным инструментом сборки, его стоят заменять только если в вашем проекте используется неподдерживаемый им синтаксис:
Expand All @@ -208,15 +210,40 @@ 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`.
Expand Down
4 changes: 4 additions & 0 deletions packages/arui-scripts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
"@babel/runtime": "^7.23.8",
"@csstools/postcss-global-data": "^2.0.1",
"@pmmmwh/react-refresh-webpack-plugin": "0.5.11",
"@swc/core": "^1.7.35",
"@swc/jest": "^0.2.36",
"assets-webpack-plugin": "7.1.1",
"autoprefixer": "^10.3.16",
"babel-core": "^7.0.0-bridge.0",
Expand Down Expand Up @@ -96,6 +98,8 @@
"shelljs": "0.8.5",
"strip-ansi": "6.0.1",
"style-loader": "3.3.3",
"swc-loader": "^0.2.6",
"swc-plugin-coverage-instrument": "^0.0.24",
"tar": "6.2.1",
"terser-webpack-plugin": "5.3.9",
"ts-jest": "28.0.8",
Expand Down
2 changes: 1 addition & 1 deletion packages/arui-scripts/src/commands/start-prod/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { configs } from '../../configs/app-configs';
import { getTscWatchCommand } from '../util/tsc';
import { runCompilers } from '../util/run-compilers';
import { getTscWatchCommand } from '../util/tsc';

process.env.BROWSERSLIST_CONFIG =
process.env.BROWSERSLIST_CONFIG || require.resolve('../../../.browserslistrc');
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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),
};
}
Expand Down
2 changes: 2 additions & 0 deletions packages/arui-scripts/src/configs/app-configs/get-defaults.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,10 +47,12 @@ export function getDefaultAppConfig(): AppConfigs {
// build tuning
keepPropTypes: false,
useTscLoader: false,
codeLoader: 'babel',
webpack4Compatibility: false,
installServerSourceMaps: false,
disableDevWebpackTypecheck: true,
jestUseTsJest: false,
jestCodeTransformer: 'babel',
collectCoverage: process.env.NODE_ENV === 'cypress' || process.env.USE_ISTANBUL === 'enabled',

// image processing
Expand Down
8 changes: 8 additions & 0 deletions packages/arui-scripts/src/configs/app-configs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,10 +42,18 @@ export type AppConfigs = {
* @deprecated использование ts-loader крайне не рекомендуется - он медленнее и не имеет преимуществ перед babel
*/
useTscLoader: boolean;
codeLoader: 'babel' | 'tsc' | 'swc';
/**
* @deprecated эта настройка будет удалена в будущих версиях скриптов
*/
webpack4Compatibility: boolean;
installServerSourceMaps: boolean;
disableDevWebpackTypecheck: boolean;
/**
* @deprecated используйте настройку jestCodeTransformer
*/
jestUseTsJest: boolean;
jestCodeTransformer: 'babel' | 'tsc' | 'swc';
collectCoverage: boolean;

// image processing
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ import { AppContextWithConfigs } from './types';

export function warnAboutDeprecations(config: AppContextWithConfigs) {
if (config.useTscLoader) {
// eslint-disable-next-line no-console
console.warn(
'Использование опции `useTscLoader` не рекомендуется и будет удалено в будущих версиях. ',
'Обратитесь к документации https://github.com/core-ds/arui-scripts/blob/master/packages/arui-scripts/docs/settings.md#usetscloader',
'для получения дополнительной информации.'
);
}

if (config.webpack4Compatibility) {
console.warn(
'Опция `webpack4Compatibility` будет удалена в будущих версиях arui-scripts.',
'Обратитесь к issue в webpack https://github.com/webpack/webpack/issues/14580 для получения дополнительной информации',
);
}
}
51 changes: 36 additions & 15 deletions packages/arui-scripts/src/configs/jest/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,10 @@
const fs = require('fs');
const { pathsToModuleNameMapper } = require('ts-jest');
const { parseConfigFileTextToJson } = require('typescript');
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 || {};
}

module.exports = {
testRegex: 'src/.*(((/__test__/|/__tests__/).*)|(test|spec|tests)).(jsx?|tsx?)$',
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx'],
Expand All @@ -26,17 +18,15 @@ module.exports = {
url: 'http://localhost',
},
transform: {
'^.+\\.jsx?$': require.resolve('./babel-transform'),
'^.+\\.mjs$': require.resolve('./babel-transform'),
'^.+\\.tsx?$': configs.jestUseTsJest
? require.resolve('ts-jest')
: require.resolve('./babel-transform'),
'^.+\\.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: '<rootDir>/' }),
...pathsToModuleNameMapper(getPathMapping(), { prefix: '<rootDir>/' }),
},
snapshotSerializers: [require.resolve('jest-snapshot-serializer-class-name-to-string')],
globals: {
Expand All @@ -45,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');
}
35 changes: 35 additions & 0 deletions packages/arui-scripts/src/configs/swc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import type { Options } from '@swc/core';

import applyOverrides from './util/apply-overrides';
import { configs } from './app-configs';

const swcConfig: Options = {
env: { coreJs: '3', mode: 'entry' },
jsc: {
parser: {
syntax: 'typescript',
tsx: true,
decorators: true,
},
loose: true,
transform: {
legacyDecorator: true,
react: {
runtime: 'automatic',
},
},
experimental: configs.collectCoverage
? {
plugins: [
['swc-plugin-coverage-instrument', {}],
],
}
: {},
},
};

export const swcClientConfig = applyOverrides(['swc', 'swcClient'], swcConfig);

export const swcServerConfig = applyOverrides(['swc', 'swcServer'], swcConfig);

export const swcJestConfig = applyOverrides(['swc', 'swcJest'], swcConfig);
6 changes: 6 additions & 0 deletions packages/arui-scripts/src/configs/util/apply-overrides.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// TODO: remove eslint-disable-next-line
import type { Configuration as WebpackConfiguration, WebpackOptionsNormalized } from 'webpack';
import type { Configuration as WebpackDevServerConfiguration } from 'webpack-dev-server';
import type { Options as SwcOptions } from '@swc/core'

import appConfigs from '../app-configs';
import { AppContextWithConfigs } from '../app-configs/types';
Expand All @@ -27,6 +28,11 @@ type Overrides = {
babelServer: any;
babelDependencies: any;

swc: SwcOptions;
swcServer: SwcOptions;
swcClient: SwcOptions;
swcJest: SwcOptions;

postcss: any[]; // TODO: где взять typedef-ы для postcss
browsers: string[];
supportingBrowsers: string[];
Expand Down
Loading
Loading