Этот материал поможет настроить path aliases для вашего cretae-react-app.
Содержание
Введение
Давайте начнем с того, зачем вообще это необходимо.
По мере роста количества компонентов и различных сервисов в вашем проекте, все чаще начинают появляться такие импорты:
Хочется заменить эти пути на что-то подобное:
Ниже я привел 2 варианта решения данной проблемы.
Import craco
Самый простой способ - это воспользоваться craco. Установив пакет и заменив скрипты, как написано в документации, вы можете приступить к созданию path aliases в файле craco.config.js.
const path = require('path');
const resolvePath = p => path.resolve(__dirname, p)
module.exports = {
// ...
webpack: {
alias: {
'@components': resolvePath('./src/components'),
'@assets': resolvePath('./src/assets'),
'@services': resolvePath('./src/services')
}
},
// ...
}
React-scripts eject
В этом методе я хочу сам поправить конфигурационные файлы, а для этого мне нужен к ним доступ. Но, будьте аккуратны, ведь действия этого скрипта НЕОТВРАТИМЫ!
npm react-scripts eject
После выполнения скрипта у вас появятся такие директории и файлы как :
Директория config/
Директория scripts/
Файл tsconfig.json (или jsconfig.json)
Изначально нужно добавить наши path aliases в tsconfig.json (или jsconfig.json). Для того, чтоб при сборке наши скрипты в директории config/ подтянули их для webpack и для jest.
{
"compilerOptions": {
// ...
"baseUrl": ".",
"paths": {
"@components/*": ["src/components/*"],
"@styled/*": ["src/components/styled/*"],
"@pages/*": ["src/pages/*"],
"@assets/*": ["src/assets/*"],
"@services/*": ["src/services/*"]
},
// ...
},
// ...
}
Далее нужно провести небольшие изменения в файле modules.js, который обрабатывает файл исправленный ранее.
'use strict'
const fs = require('fs')
const path = require('path')
const paths = require('./paths')
const chalk = require('react-dev-utils/chalk')
const resolve = require('resolve')
const removeWildcardPart = p => p.replace('/*', '');
// converts "src/components/*" to "src/components"
// ...
function getWebpackAliases(options = {}) {
const baseUrl = options.baseUrl
if (!baseUrl) {
return {}
}
let resultAlias = {src: paths.appSrc}
return Object.assign({}, resultAlias,
Object.keys(options.paths).reduce(
(obj, alias) => {
obj[removeWildcardPart(alias)] =
options.paths[alias].map(removeWildcardPart)[0]
return obj
}, {}
)
)
}
// ...
function getJestAliases(options = {}) {
const baseUrl = options.baseUrl
if (!baseUrl) {
return {}
}
let resultAlias = {'^src/(.*)$': '<rootDir>/src/$1'}
return Object.assign({}, resultAlias,
Object.keys(options.paths).reduce(
(obj, alias) => {
obj[`^${removeWildcardPart(alias)}(.*)$`] =
options.paths[alias]
.map(p => `<rootDir>/src/${removeWildcardPart(p)}/$1`)
return obj
}, {}
)
)
}
// ...
Теперь наш проект успешно работает с созданными нами path aliases.
Пользуйтесь на здоровье!
DmitryKazakov8
"действия этого скрипта НЕОТВРАТИМЫ" — точно сказано, почти все проекты, которые видел использующими CRA, сделали eject и перешли на кастомные конфиги по мере роста проекта. Он только для маленьких pet-проджектов, так как для проектов чуть больше нужно много дополнительного функционала, а возня с переопределением правил изначально плохая идея.
По телу статьи — вы забыли упомянуть, что в IDE может потребоваться специальным образом отметить папки, для которых сделаны алиасы — так, WebStorm умеет брать ts-алиасы в ts-файлах, но в стилевых файлах
@import 'mixins.scss'
не сработает без отметки Resource Root на папкеsrc/components/styles
. У вас вижу css-in-js, поэтому могли не столкнуться. Также в кодовых блоках лучше использовать двойной пробел для табуляции и переносить при достижении 80-100 символов — читать легче, не будет прокрутки.За лесенку в
const ... = require()
уважение, выглядит аккуратно. Жаль, не разбито по семантическим группам (built-ins, external, internal etc.), в этом случае скорость восприятия кода еще улучшится.По коду еще по неймингу захотелось пройтись. Вот, к примеру, функция
Как видно из названия, она "нарезает путь". Из реализации не очень понятно, что ожидается на вход и что будет на выходе. Даже если найти пример входных данных в коде (
"src/components/*"
), все равно не сразу понятно, что будет на выходе — обрежется только звездочка или еще что-то. Только поразбиравшись станет понятно, что на выходе получится"src/components"
. Почему бы не сделать более читабельно:Примерно то же и с
.reduce((obj, x) => { ... })
. Так как тут не используется TypeScript, то главным оружием в борьбе за понятность структур в коде является семантичность. И вариант с.reduce((acc, path) => { ... })
будет выглядеть лучше, а еще лучше — вынести это в отдельную функцию, чтобы следующий разработчик не тратил время на разбор, если его это не интересует. К тому же эти вездесущие неймингиx
— в последнем кодовом блоке возник дубляж названий:а это уже тянет на вопрос юниору на собеседованиях — какие недостатки у подобного подхода) А так норм, добро пожаловать в писательское сообщество.
Mogu4iy Автор
Спасибо, нейминг функции и переменных исправил) А с проблемами восприятия EDA и правда пока не сталкивался.