Irbisa · Шпаргалка

Инструменты и сборка фронтенда

Бандлеры, Vite и webpack, esbuild, SWC и Babel, tree shaking, Fast Refresh, source maps, переменные окружения, целевые браузеры и полифилы, npm, semver и lockfile, линтинг, безопасность зависимостей

Middle-разработчик · 18 вопросов

  1. 01

    Что делает бандлер и зачем собирать бандл для продакшена, если браузеры уже поддерживают ES-модули?

    Бандлер начинает с входного файла, проходит по всем import, преобразует то, что браузер не может выполнить как есть (TypeScript, JSX, импорты CSS, картинки), и записывает несколько оптимизированных файлов.

  2. 02

    Как работают переменные окружения в приложении на Vite и почему ключ из VITE_API_KEY виден каждому пользователю?

    Vite читает файлы .env во время сборки и подставляет вместо каждого обращения import.meta.env.VITE_* его буквальное значение прямо в итоговый JavaScript.

    // .env               VITE_API_URL=http://localhost:8080// .env.production    VITE_API_URL=https://api.example.com// .env.local         API_SECRET=change-me (no prefix, git-ignored) // replaced with the literal string at build timeconst apiUrl = import.meta.env.VITE_API_URL;…
  3. 03

    Чем отличаются зависимости dependencies, devDependencies и peerDependencies в файле package.json?

    dependencies нужны вашему коду во время работы, devDependencies нужны только для сборки, тестов и линтинга, а peerDependencies описывают пакеты, которые библиотека ожидает получить от приложения-хоста, чтобы у приложения и библиотеки была одна общая копия.

    {  "name": "@acme/date-picker",  "version": "2.1.0",  "dependencies": {    "date-fns": "^4.1.0"  },…
  4. 04

    Что означают ^1.2.3 и ~1.2.3 в package.json и зачем коммитить lock-файл и запускать npm ci в CI?

    ^1.2.3 принимает любую 1.x.x начиная с 1.2.3 (новые минорные версии и патчи), ~1.2.3 принимает только патчи 1.2.x.

    ^1.2.3   >=1.2.3 <2.0.0   new minor and patch versions~1.2.3   >=1.2.3 <1.3.0   new patch versions only^0.2.3   >=0.2.3 <0.3.0   below 1.0.0 a minor bump counts as breaking1.2.3    exactly 1.2.3 npm install   resolves the ranges, may rewrite package-lock.json…
  5. 05

    Как Vite работает в разработке и при продакшен-сборке и почему его дев-сервер стартует быстрее, чем у webpack?

    В разработке Vite не собирает ваш код в бандл: он один раз пре-бандлит зависимости, а исходники отдаёт как нативные ES-модули и преобразует каждый файл в момент запроса браузера.

  6. 06

    Что такое Hot Module Replacement и как React Fast Refresh сохраняет стейт компонента, когда вы сохраняете файл?

    HMR подменяет изменённый модуль на работающей странице без перезагрузки: дев-сервер присылает изменение по WebSocket, а ближайший модуль, который принимает обновления, применяет его.

  7. 07

    Найдите баг: каждая правка ThemeProvider.tsx перезагружает всю страницу и стирает наполовину заполненную форму вместо горячего обновления.

    // ThemeProvider.tsx (main.tsx renders <ThemeProvider><App /></ThemeProvider>)import { createContext, useContext, type ReactNode } from 'react'; export const ThemeContext = createContext<'light' | 'dark'>('light'); export function ThemeProvider({ children }: { children: ReactNode }) {  return <ThemeContext value="dark">{children}</ThemeContext>;} export function useTheme() {  return useContext(ThemeContext);}

    Файл экспортирует объект ThemeContext и хук useTheme рядом с компонентом, поэтому Fast Refresh не может обновить его на месте.

  8. 08

    Чем в webpack лоадер отличается от плагина?

    Лоадер преобразует по одному файлу в момент, когда webpack его импортирует, например TypeScript в JavaScript или Sass в CSS.

    // webpack.config.jsconst HtmlWebpackPlugin = require('html-webpack-plugin');const MiniCssExtractPlugin = require('mini-css-extract-plugin'); module.exports = {  entry: './src/main.tsx',…
  9. 09

    Чем транспиляция отличается от бандлинга и что делают Babel, SWC, esbuild и tsc в сборке React-приложения?

    Транспиляция переписывает синтаксис одного файла в другую форму (TypeScript и JSX в обычный JavaScript, новый синтаксис в более старый), а бандлинг проходит по импортам между файлами и собирает результат в чанки.

    // types.tsexport interface User {  id: string;  name: string;}export const GUEST: User = { id: '0', name: 'Guest' };…
  10. 10

    Какие из этих импортов бандлер может удалить через tree shaking и что мешает удалить остальные?

    // utils.ts exports formatPrice and parseCsvimport { formatPrice } from './utils';// lodash ships CommonJS, lodash-es ships ES modules with "sideEffects": falseimport { debounce } from 'lodash';import { throttle } from 'lodash-es';// dates.ts exports 40 small date helpersimport * as dates from './dates';// setupI18n.ts calls i18n.init() at the top levelimport './setupI18n'; export function bind(input: HTMLInputElement, helper: keyof typeof dates) {  const fmt = dates[helper]; // chosen at runtime  input.oninput = debounce(() => fmt(input.value), 300);  window.onscroll = throttle(() => console.log(formatPrice(9.99)), 100);}

    Удаляются только неиспользуемый parseCsv из ./utils и ненужные части lodash-es.

  11. 11

    Зачем продакшен-сборка добавляет хеш в имя каждого файла и когда файл кладут в public/, а не импортируют?

    Хеш вычисляется по содержимому файла, поэтому файл сохраняет свой URL, пока содержимое не изменится, и получает новый, когда оно меняется.

    import logoUrl from './assets/logo.svg'; // becomes /assets/logo-<hash>.svgimport heroUrl from './assets/hero.webp'; export function Header() {  return (    <header>…
  12. 12

    Что такое source maps и нужно ли выкладывать их в продакшен?

    Source map (карта исходного кода) представляет собой файл .map, который сопоставляет каждую позицию в минифицированном бандле с исходным файлом, строкой и именем, чтобы DevTools и трекеры ошибок показывали ваш настоящий код.

    import { defineConfig } from 'vite';import react from '@vitejs/plugin-react';import { sentryVitePlugin } from '@sentry/vite-plugin'; export default defineConfig({  build: {…
  13. 13

    Как решить, какие браузеры поддерживать, и как связаны browserslist, транспиляция синтаксиса и полифилы?

    Решайте по аналитике ваших пользователей и требованиям бизнеса, запишите решение в виде запроса browserslist и дайте инструментам работать от него: транспайлеры переписывают новый синтаксис под эти браузеры, а полифилы добавляют API, которых в них нет.

    import { defineConfig } from 'vite';import react from '@vitejs/plugin-react';import legacy from '@vitejs/plugin-legacy'; export default defineConfig({  // syntax is lowered to this list; no polyfills are added…
  14. 14

    Чем отличаются npm, Yarn и pnpm и что такое фантомная зависимость?

    Все три ставят пакеты из реестра npm, а различаются тем, как раскладывают node_modules.

  15. 15

    Что ловит ESLint такого, чего не ловит TypeScript, и как разделить работу между ESLint, Prettier и tsc в CI?

    TypeScript проверяет, что типы сходятся, а ESLint проверяет шаблоны, которые проходят проверку типов, но оказываются багами или плохой практикой: хук, вызванный по условию, пропущенная зависимость эффекта, промис, который никто не ждёт.

    // eslint.config.jsimport js from '@eslint/js';import tseslint from 'typescript-eslint';import reactHooks from 'eslint-plugin-react-hooks';import { reactRefresh } from 'eslint-plugin-react-refresh';import { defineConfig, globalIgnores } from 'eslint/config';…
  16. 16

    Что делает поле exports в package.json и почему пакет иногда ломается при импорте из ESM или CommonJS?

    exports задаёт публичную карту точек входа пакета: все пути, которые можно импортировать, и для каждого условия (types, import, require, default) файл, в который путь разрешается; всё, чего нет в списке, импортировать нельзя.

    {  "name": "@acme/date-utils",  "version": "2.0.0",  "type": "module",  "exports": {    ".": {…
  17. 17

    Дев-сервер стартует минуту, а продакшен-сборка идёт десять. Как найти причину и ускорить их?

    Сначала измерьте, а потом меняйте: засеките каждый шаг отдельно и профилируйте бандлер.

  18. 18

    Как защитить фронтенд-проект от скомпрометированного или вредоносного npm-пакета?

    Относитесь к каждой зависимости как к коду, который могут перехватить: ставьте только то, что закреплено в lock-файле, не торопитесь брать только что вышедшие версии, блокируйте install-скрипты, держите секреты вне досягаемости установки и не раздувайте список зависимостей.

    # pnpm-workspace.yamlminimumReleaseAge: 1440      # minutes: skip versions published less than a day agominimumReleaseAgeExclude:  - '@acme/*'                # our own packages may update at onceallowBuilds:                 # the only dependencies allowed to run install scripts  esbuild: true…