UNPKG

@shopify/react-server

Version:
134 lines (118 loc) 3.94 kB
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var path = require('path'); var webpack = require('webpack'); var VirtualModulesPlugin = require('webpack-virtual-modules'); var shared = require('./shared.js'); var utilities = require('./error/utilities.js'); function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; } var VirtualModulesPlugin__default = /*#__PURE__*/_interopDefaultLegacy(VirtualModulesPlugin); /** * A webpack plugin that generates default server and client entrypoints if none are present. * @param config * @returns a customized webpack plugin */ class ReactServerPlugin { constructor({ host, port, assetPrefix, basePath = '.', proxy = false } = {}) { this.options = { basePath, host, port, assetPrefix, proxy }; } apply(compiler) { const modules = this.modules(compiler); const virtualModules = new VirtualModulesPlugin__default["default"](modules); virtualModules.apply(compiler); const ignorePaths = Object.keys(modules).concat(compiler.options.watchOptions.ignored || []); const watchIgnore = new webpack.WatchIgnorePlugin({ paths: ignorePaths }); watchIgnore.apply(compiler); } modules(compiler) { const { basePath } = this.options; const modules = {}; if (shared.noSourceExists(shared.Entrypoint.Client, this.options, compiler)) { const file = path.join(basePath, `${shared.Entrypoint.Client}.js`); modules[file] = clientSource(); } if (shared.noSourceExists(shared.Entrypoint.Server, this.options, compiler)) { const file = path.join(basePath, `${shared.Entrypoint.Server}.js`); modules[file] = serverSource(this.options, compiler); } if (utilities.errorSSRComponentExists(this.options, compiler)) { const file = path.join(basePath, `${shared.Entrypoint.Error}.entry.client.js`); modules[file] = utilities.errorClientSource(); } return modules; } } function serverSource(options, compiler) { const { port, host, assetPrefix, proxy } = options; return ` ${shared.HEADER} import React from 'react'; import {createServer} from '@shopify/react-server'; import App from 'index'; ${utilities.errorSSRComponentExists(options, compiler) ? "import Error from 'error';" : ''} process.on('uncaughtException', logError); process.on('unhandledRejection', logError); function logError(error) { const errorLog = \`\${error.stack || error.message || 'No stack trace was present'}\`; console.log(\`React Server failed to start.\n\${errorLog}\`); process.exit(1); } const render = (ctx) => { return React.createElement(App, { url: ctx.request.URL, data: ctx.state.quiltData, }); } const app = createServer({ port: ${port}, ip: ${JSON.stringify(host)}, assetPrefix: ${JSON.stringify(assetPrefix)}, proxy: ${proxy}, render, ${utilities.errorSSRComponentExists(options, compiler) ? `renderError: (ctx) => { return React.createElement(Error, { url: ctx.request.url, data: ctx.state.quiltData, error: ctx.state.quiltError, }); }` : ''} }); export default app; `; } function clientSource() { return ` ${shared.HEADER} import React from 'react'; import ReactDOM from 'react-dom/client'; import {showPage, getSerialized} from '@shopify/react-html'; import App from 'index'; const appContainer = document.getElementById('app'); const data = getSerialized('quilt-data'); const url = new URL(window.location.href); ReactDOM.hydrateRoot(appContainer, React.createElement(App, {data, url})); showPage(); `; } exports.ReactServerPlugin = ReactServerPlugin;