Для серверного рендера создаётся своя сборка. Используется общий файл настроек /webpack.config.js
.
В зависимости от назначения сборки меняется параметр libraryTarget
на 'commonjs2'
и входной файл приложения в entry
на 'index.node.js'
.
Опции модулей, траспиляции и прочего одинаковые.
let config = {
name: target, // "web" или "node" передаётся в параметрах запуска сборки
target: target,
mode: process.env.NODE_ENV, // https://webpack.js.org/configuration/mode/
entry: [`index.${target}.js`], //index.node.js или index.web.js
output: {
path: path.join(__dirname, 'dist', target), // В разные папки сборки
libraryTarget: isNode ? 'commonjs2' : undefined, // Для Node.js используется модули в CommonJS
//...
},
//...
}
Чтобы в логике приложения учитывать режим запуска, в сборке определены константы:
TARGET
: string - oneOf('web', 'node')IS_WEB
: boolean // признак, приложение для браузераIS_NODE
: boolean // признак, приложение для сервераПример в коде приложения
if (process.env.IS_NODE) {
// приложение запущено на Node.js
}
if (process.env.IS_WEB) {
// приложение запущено в браузере
}
Для запуска приложения с серверным рендером используется команда:
npm run start:ssr
Запуск SSR в режиме продакшена, т.е. запускается сборка. Поэтому автоматически будут созданы новые сборки для Node.js и web.
Отдельно сборка выполняется командой npm run build:ssr
. Нужно не забывать делать сборку и для веба npm run build
.
Можно одной командой все сразу:
npm run build:all
На продакшен сервере пересобирать приложение не надо, остаётся только запустить. Поэтому npm команда start не подойдет (так как делает сборку),
лучше напрямую запустить Node.js с файлом /server.js
. Этот файл не попадает в сборку, не является частью фронтенд приложения,
а содержит логику http сервера и сам запускает сборку фронта под Node.js для обработки запросов.
node ./server.js
Про команды сборки и запуска SSR.
В сборку попадают все используемые пакеты из /node_modules
. На сервере не надо устанавливать npm пакеты.
Более того, пакеты для фронта часто оказываются нерабочими в среде node.js. Сборка всех пакетов через webpack решает эту проблему.
При желании из сборки можно исключить кроссплатформенные пакеты, указав их названия в опции вебпака externals
.
Node.js будет искать тогда пакет в директории /node_modules
.
if (isNode) {
config.externals = ['react-helmet', 'moment'];
}
В теории приложение на сервере можно было бы запускать без сборки. Синтаксические особенности javascript, которые не поддерживает Node.js (их немного), можно активировать через транспиляцию в runtime режиме библиотеками babel-runtime или core-js. Куда сложнее проблема импорта не js файлов в Node.js. Webpack позволяет импортировать любые файлы, описывав способ импорта в опциях
module.rules
. Для Node.js нужно глобально переопределить функцию require() (пример) и на все кастомные типы файлов реализовывать особый импорт. Например, импорт png файла — это генерация относительного url или base64 ссылки. Импорт стилей просто игнорируется, либо формируется объект с хэшами всех ccs-классов. Есть библиотеки, которые анализирую, как вебпак импортировал для веба файл и повторяют логику для ноды. Варианты решений без сборки под Node.js постоянно натыкались на грабли совместимости, корректности путей, лишних оберток. Надежное и простое решение — делать отдельную сборку для Node.js.