Repository: jaredpalmer/razzle Branch: master Commit: 54724b7bb810 Files: 1039 Total size: 1.1 MB Directory structure: gitextract__2juu5zg/ ├── .all-contributorsrc ├── .changeset/ │ └── config.json ├── .eslintignore ├── .eslintrc ├── .github/ │ ├── CODE_OF_CONDUCT.md │ ├── CONTRIBUTING.md │ ├── FUNDING.yml │ ├── ISSUE_TEMPLATE/ │ │ ├── Bug_report.md │ │ ├── Documentation.md │ │ ├── Feature_request.md │ │ └── Question.md │ ├── labels.yml │ ├── stale.yml │ └── workflows/ │ ├── examples.yml │ ├── examples_node14.yml │ ├── label.yml │ ├── nodejs.yml │ ├── release.yml │ └── test-examples.yml ├── .gitignore ├── .prettierrc ├── LICENSE ├── examples/ │ ├── .gitignore │ ├── basic/ │ │ ├── README.md │ │ ├── gitignore │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── sandbox.config.json │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── basic-server/ │ │ ├── README.md │ │ ├── gitignore │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ ├── sandbox.config.json │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── index.js │ │ └── server.js │ ├── basic-serverless/ │ │ ├── README.md │ │ ├── gitignore │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ ├── sandbox.config.json │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── basic-spa/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ ├── index.html │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ └── client.js │ ├── with-afterjs/ │ │ └── README.md │ ├── with-custom-babel-config/ │ │ ├── .babelrc │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── Home.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-custom-devserver-options/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-custom-environment-variables/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-custom-target-babel-config/ │ │ ├── .babelrc.node │ │ ├── .babelrc.web │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── Home.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-custom-webpack-config/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-devcert-https/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-development-build/ │ │ ├── README.md │ │ ├── gitignore │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── sandbox.config.json │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-elm/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── elm-package.json │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.elm │ │ ├── Main.elm │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-esbuild-loader/ │ │ ├── .eslintrc.js │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ ├── src/ │ │ │ ├── App.css │ │ │ ├── App.test.tsx │ │ │ ├── App.tsx │ │ │ ├── Home.css │ │ │ ├── Home.tsx │ │ │ ├── client.tsx │ │ │ ├── index.ts │ │ │ └── server.tsx │ │ ├── tsconfig.json │ │ └── typings/ │ │ └── index.d.ts │ ├── with-eslint/ │ │ ├── .eslintrc.json │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ ├── sandbox.config.json │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-experimental-refresh/ │ │ ├── README.md │ │ ├── package.json │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── components/ │ │ │ ├── ClickCount.js │ │ │ └── ClickCount.module.css │ │ ├── global.css │ │ ├── index.js │ │ └── server.js │ ├── with-fastify/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── src/ │ │ │ ├── App.css │ │ │ ├── App.test.tsx │ │ │ ├── App.tsx │ │ │ ├── Home.css │ │ │ ├── Home.tsx │ │ │ ├── client.tsx │ │ │ ├── index.ts │ │ │ ├── server.tsx │ │ │ └── setupTests.ts │ │ ├── tsconfig.json │ │ └── typings/ │ │ └── svg.d.ts │ ├── with-firebase-functions/ │ │ ├── .firebaserc │ │ ├── .gitignore │ │ ├── README.md │ │ ├── firebase.json │ │ ├── index.js │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-heroku/ │ │ ├── .gitignore │ │ ├── Procfile │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-hyperapp/ │ │ ├── .babelrc │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ ├── main.js │ │ ├── main.test.js │ │ └── server.js │ ├── with-inferno/ │ │ ├── .babelrc │ │ ├── .eslintrc │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-jest-snapshots/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.js │ │ ├── Home.js │ │ ├── __tests__/ │ │ │ ├── App.test.js │ │ │ ├── Home.test.js │ │ │ └── __snapshots__/ │ │ │ ├── App.test.js.snap │ │ │ └── Home.test.js.snap │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-jsconfig-paths/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── here-is-extra/ │ │ │ └── extra.js │ │ ├── jsconfig.json │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── sandbox.config.json │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-jsxstyle/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── About.js │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── Home.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-koa/ │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── Home.css │ │ ├── Home.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-less/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── App.less │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ ├── other.less │ │ └── server.js │ ├── with-loadable-components/ │ │ ├── .babelrc │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── Body.js │ │ ├── BodyPart.js │ │ ├── Footer.js │ │ ├── Header.js │ │ ├── client.js │ │ ├── index.js │ │ ├── server.js │ │ └── static_export.js │ ├── with-material-ui/ │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ ├── server.js │ │ └── theme.js │ ├── with-mdx/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── client.js │ │ ├── example.md │ │ ├── index.js │ │ └── server.js │ ├── with-module-federation/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── basic-1/ │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ ├── index.html │ │ │ │ └── robots.txt │ │ │ ├── razzle.config.js │ │ │ └── src/ │ │ │ ├── App.js │ │ │ ├── Button.js │ │ │ ├── bootstrap.js │ │ │ └── client.js │ │ ├── basic-2/ │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ ├── index.html │ │ │ │ └── robots.txt │ │ │ ├── razzle.config.js │ │ │ └── src/ │ │ │ ├── App.js │ │ │ ├── Button.js │ │ │ ├── bootstrap.js │ │ │ └── client.js │ │ └── package.json │ ├── with-monorepo/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── basic-1/ │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ └── robots.txt │ │ │ └── src/ │ │ │ ├── App.css │ │ │ ├── App.js │ │ │ ├── App.test.js │ │ │ ├── client.js │ │ │ ├── index.js │ │ │ └── server.js │ │ ├── basic-2/ │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ └── robots.txt │ │ │ └── src/ │ │ │ ├── App.css │ │ │ ├── App.js │ │ │ ├── App.test.js │ │ │ ├── client.js │ │ │ ├── index.js │ │ │ └── server.js │ │ └── package.json │ ├── with-monorepo-without-workspaces/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── basic-1/ │ │ │ ├── public/ │ │ │ │ └── robots.txt │ │ │ └── src/ │ │ │ ├── App.css │ │ │ ├── App.js │ │ │ ├── App.test.js │ │ │ ├── client.js │ │ │ ├── index.js │ │ │ └── server.js │ │ ├── basic-2/ │ │ │ ├── public/ │ │ │ │ └── robots.txt │ │ │ └── src/ │ │ │ ├── App.css │ │ │ ├── App.js │ │ │ ├── App.test.js │ │ │ ├── client.js │ │ │ ├── index.js │ │ │ └── server.js │ │ └── package.json │ ├── with-now/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-now-v2/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── now.json │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-polka/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-preact/ │ │ ├── .babelrc │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-promise-config/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-react-native-web/ │ │ ├── .babelrc │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-react-router/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── About.js │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── Home.js │ │ ├── client.js │ │ ├── index.js │ │ ├── server.js │ │ └── static_export.js │ ├── with-react-server-components/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── notes/ │ │ │ ├── .gitkeep │ │ │ ├── 1.md │ │ │ ├── 2.md │ │ │ ├── 3.md │ │ │ └── 4.md │ │ ├── package.json │ │ ├── plugin/ │ │ │ ├── ReactFlightWebpackLoader.js │ │ │ ├── ReactFlightWebpackLoader.ts │ │ │ ├── ReactFlightWebpackNodeLoader.js │ │ │ ├── ReactFlightWebpackNodeLoader.ts │ │ │ ├── ReactFlightWebpackNodeRegister.js │ │ │ ├── ReactFlightWebpackNodeRegister.ts │ │ │ ├── ReactFlightWebpackPlugin.js │ │ │ ├── ReactFlightWebpackPlugin.ts │ │ │ └── __tests__/ │ │ │ ├── ReactFlightWebpackPlugin.spec.ts │ │ │ └── fixture/ │ │ │ ├── Form.client.js │ │ │ ├── FormServer.server.js │ │ │ ├── entry.js │ │ │ └── package.json │ │ ├── public/ │ │ │ ├── index.html │ │ │ ├── robots.txt │ │ │ └── style.css │ │ ├── razzle.config.js │ │ ├── sandbox.config.json │ │ ├── scripts/ │ │ │ └── seed.js │ │ └── src/ │ │ ├── App.server.tsx │ │ ├── Cache.client.tsx │ │ ├── EditButton.client.tsx │ │ ├── LocationContext.client.tsx │ │ ├── Note.server.tsx │ │ ├── NoteEditor.client.tsx │ │ ├── NoteList.server.tsx │ │ ├── NoteListSkeleton.tsx │ │ ├── NotePreview.tsx │ │ ├── NoteSkeleton.tsx │ │ ├── Root.client.tsx │ │ ├── SearchField.client.tsx │ │ ├── SidebarNote.client.tsx │ │ ├── SidebarNote.tsx │ │ ├── Spinner.tsx │ │ ├── TextWithMarkdown.tsx │ │ ├── cli.server.js │ │ ├── db.server.ts │ │ ├── index.client.tsx │ │ └── index.server.ts │ ├── with-reason-react/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── bsconfig.json │ │ ├── jsconfig.json │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.re │ │ ├── CommentList.css │ │ ├── CommentList.re │ │ ├── CommentsPage.css │ │ ├── CommentsPage.re │ │ ├── NotFound.css │ │ ├── NotFound.re │ │ ├── StoryData.re │ │ ├── StoryListItem.css │ │ ├── StoryListItem.re │ │ ├── TopStoriesPage.re │ │ ├── Utils.re │ │ ├── client.js │ │ ├── index.js │ │ ├── index.re │ │ ├── link.re │ │ ├── registerServiceWorker.js │ │ └── server.js │ ├── with-redux/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── client/ │ │ │ └── index.js │ │ ├── common/ │ │ │ ├── actions/ │ │ │ │ └── index.js │ │ │ ├── api/ │ │ │ │ └── counter.js │ │ │ ├── components/ │ │ │ │ └── Counter.js │ │ │ ├── containers/ │ │ │ │ └── App.js │ │ │ ├── reducers/ │ │ │ │ ├── counter.js │ │ │ │ └── index.js │ │ │ └── store/ │ │ │ └── configureStore.js │ │ ├── index.js │ │ └── server/ │ │ └── index.js │ ├── with-scss/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── App.scss │ │ ├── App.test.js │ │ ├── app.module.scss │ │ ├── client.js │ │ ├── index.js │ │ ├── other.scss │ │ └── server.js │ ├── with-scss-options/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── App.scss │ │ ├── App.test.js │ │ ├── app.module.scss │ │ ├── client.js │ │ ├── index.js │ │ ├── other.scss │ │ ├── prepend.scss │ │ └── server.js │ ├── with-single-exposed-port/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-styled-components/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-svelte/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ ├── sandbox.config.json │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-tailwindcss/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ ├── sandbox.config.json │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-typeorm-graphql/ │ │ ├── .babelrc │ │ ├── .eslintrc.js │ │ ├── .gitignore │ │ ├── .prettierrc │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ ├── src/ │ │ │ ├── App.css │ │ │ ├── App.test.tsx │ │ │ ├── App.tsx │ │ │ ├── Home.css │ │ │ ├── Home.tsx │ │ │ ├── client.tsx │ │ │ ├── database/ │ │ │ │ └── init_db.ts │ │ │ ├── declarations.d.ts │ │ │ ├── index.ts │ │ │ ├── models/ │ │ │ │ ├── Abilities.ts │ │ │ │ ├── Pokemon.ts │ │ │ │ ├── PokemonAbilities.ts │ │ │ │ ├── Types.ts │ │ │ │ └── index.ts │ │ │ ├── schema/ │ │ │ │ ├── Resolvers.ts │ │ │ │ └── index.ts │ │ │ ├── server.tsx │ │ │ └── setupTests.ts │ │ └── tsconfig.json │ ├── with-typescript/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── src/ │ │ │ ├── App.css │ │ │ ├── App.test.tsx │ │ │ ├── App.tsx │ │ │ ├── Home.css │ │ │ ├── Home.tsx │ │ │ ├── client.tsx │ │ │ ├── declarations.d.ts │ │ │ ├── index.ts │ │ │ ├── server.tsx │ │ │ └── setupTests.ts │ │ └── tsconfig.json │ ├── with-typescript-plugin/ │ │ ├── .eslintrc.js │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ ├── src/ │ │ │ ├── App.css │ │ │ ├── App.test.tsx │ │ │ ├── App.tsx │ │ │ ├── Home.css │ │ │ ├── Home.tsx │ │ │ ├── client.tsx │ │ │ ├── index.ts │ │ │ └── server.tsx │ │ ├── tsconfig.json │ │ └── typings/ │ │ └── index.d.ts │ ├── with-vendor-bundle/ │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-vue/ │ │ ├── .eslintrc │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── App.js │ │ ├── App.vue │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── with-vue-router/ │ │ ├── .eslintrc │ │ ├── .gitignore │ │ ├── README.md │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ └── src/ │ │ ├── About.vue │ │ ├── App.js │ │ ├── App.vue │ │ ├── Home.vue │ │ ├── PageNotFound.vue │ │ ├── client.js │ │ ├── index.js │ │ ├── router.js │ │ └── server.js │ ├── with-webpack-dev-server-v4/ │ │ ├── README.md │ │ ├── gitignore │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── razzle.config.js │ │ ├── sandbox.config.json │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ └── with-webpack-public-path/ │ ├── README.md │ ├── package.json │ ├── public/ │ │ └── robots.txt │ ├── sandbox.config.json │ └── src/ │ ├── App.css │ ├── App.js │ ├── App.test.js │ ├── client.js │ ├── index.js │ ├── init.client.js │ ├── init.server.js │ ├── real.client.js │ ├── real.server.js │ └── server.js ├── lerna.json ├── package.json ├── package.meta.json ├── packages/ │ ├── babel-preset-razzle/ │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── babel-plugins/ │ │ │ ├── commonjs.js │ │ │ ├── jsx-pragma.js │ │ │ ├── no-anonymous-default-export.js │ │ │ └── optimize-hook-destructuring.js │ │ ├── index.js │ │ └── package.json │ ├── create-razzle-app/ │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── bin/ │ │ │ └── create-razzle-app │ │ ├── index.js │ │ ├── lib/ │ │ │ ├── index.js │ │ │ ├── messages.js │ │ │ ├── officialExamples.js │ │ │ └── utils/ │ │ │ ├── copy-dir.js │ │ │ ├── get-install-cmd.js │ │ │ ├── install.js │ │ │ ├── load-example.js │ │ │ ├── load-git-example.js │ │ │ ├── load-github-example.js │ │ │ ├── load-npm-example.js │ │ │ └── output.js │ │ ├── package.json │ │ └── templates/ │ │ └── default/ │ │ ├── README.md │ │ ├── gitignore │ │ ├── package.json │ │ ├── public/ │ │ │ └── robots.txt │ │ ├── sandbox.config.json │ │ └── src/ │ │ ├── App.css │ │ ├── App.js │ │ ├── App.test.js │ │ ├── Home.css │ │ ├── Home.js │ │ ├── client.js │ │ ├── index.js │ │ └── server.js │ ├── razzle/ │ │ ├── .gitignore │ │ ├── CHANGELOG.md │ │ ├── LICENSE │ │ ├── README.md │ │ ├── babel.js │ │ ├── bin/ │ │ │ └── razzle.js │ │ ├── config/ │ │ │ ├── babel-loader/ │ │ │ │ └── razzle-babel-loader.js │ │ │ ├── createConfigAsync.js │ │ │ ├── createJestConfig.js │ │ │ ├── createRazzleTestConfig.js │ │ │ ├── defaultOptions.js │ │ │ ├── env.js │ │ │ ├── jest/ │ │ │ │ ├── babelTransform.js │ │ │ │ ├── cssTransform.js │ │ │ │ └── fileTransform.js │ │ │ ├── loadPlugins.js │ │ │ ├── loadRazzleConfig.js │ │ │ ├── modules.js │ │ │ ├── paths.js │ │ │ └── razzleDevServer.js │ │ ├── package.json │ │ └── scripts/ │ │ ├── build.js │ │ ├── export.js │ │ ├── start.js │ │ └── test.js │ ├── razzle-dev-utils/ │ │ ├── CHANGELOG.md │ │ ├── FileSizeReporter.js │ │ ├── FriendlyErrorsPlugin.js │ │ ├── README.md │ │ ├── WebpackConfigHelpers.js │ │ ├── devServerMajor.js │ │ ├── formatWebpackMessages.js │ │ ├── logger.js │ │ ├── makeLoaderFinder.js │ │ ├── package.json │ │ ├── prettyNodeErrors.js │ │ ├── printErrors.js │ │ ├── printWarnings.js │ │ ├── resolveRequest.js │ │ ├── setPorts.js │ │ ├── webpackHotDevClient.js │ │ ├── webpackHotDevClientV4.js │ │ └── webpackMajor.js │ ├── razzle-plugin-bundle-analyzer/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ ├── package.json │ │ └── tests/ │ │ └── index.test.js │ ├── razzle-plugin-css/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ ├── razzle-plugin-devcert/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ ├── razzle-plugin-elm/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ ├── razzle-plugin-eslint/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ ├── razzle-plugin-graphql/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── helpers.js │ │ ├── index.js │ │ ├── package.json │ │ └── tests/ │ │ └── index.test.js │ ├── razzle-plugin-inferno/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ ├── razzle-plugin-less/ │ │ ├── .eslintrc │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── helpers.js │ │ ├── index.js │ │ ├── package.json │ │ └── tests/ │ │ └── index.test.js │ ├── razzle-plugin-manifest/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ ├── razzle-plugin-mdx/ │ │ ├── .eslintrc │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── helpers.js │ │ ├── index.js │ │ ├── package.json │ │ └── tests/ │ │ └── index.test.js │ ├── razzle-plugin-php/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ ├── razzle-plugin-preact/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ ├── razzle-plugin-react/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ ├── razzle-plugin-scss/ │ │ ├── .eslintrc │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── helpers.js │ │ ├── index.js │ │ ├── package.json │ │ └── tests/ │ │ └── index.test.js │ ├── razzle-plugin-svelte/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── helpers.js │ │ ├── index.js │ │ ├── package.json │ │ └── tests/ │ │ └── index.test.js │ ├── razzle-plugin-typescript/ │ │ ├── .eslintrc │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── helpers.js │ │ ├── index.js │ │ ├── package.json │ │ └── tests/ │ │ └── index.test.js │ ├── razzle-plugin-vue/ │ │ ├── CHANGELOG.md │ │ ├── README.md │ │ ├── index.js │ │ └── package.json │ └── razzle-start-server-webpack-plugin/ │ ├── .babelrc │ ├── .nvmrc │ ├── CHANGELOG.md │ ├── LICENSE │ ├── README.md │ ├── dist/ │ │ ├── StartServerPlugin.js │ │ ├── monitor-loader.js │ │ └── monitor.js │ ├── package.json │ ├── src/ │ │ ├── StartServerPlugin.js │ │ ├── monitor-loader.js │ │ └── monitor.js │ └── tests/ │ ├── SilentPlugin.js │ ├── cases/ │ │ ├── test-project/ │ │ │ ├── index.js │ │ │ └── webpack.config.js │ │ └── test-project-hmr/ │ │ ├── index.js │ │ └── webpack.config.js │ ├── index.test.js │ ├── js/ │ │ ├── test-project/ │ │ │ └── server.js │ │ └── test-project-hmr/ │ │ └── server.js │ ├── test-project.sh │ └── utils.js ├── scripts/ │ ├── bootstrap-examples.js │ ├── build-docs.js │ ├── exampleDependencyVersions.json │ ├── internalPeerDependencyVersions.json │ ├── new-example.js │ ├── publish-all.js │ ├── publish-to-npm.js │ ├── release-notes.js │ ├── try-example.js │ ├── update-examples.js │ └── yalc-publish-all.js ├── test/ │ ├── e2e/ │ │ ├── create-razzle-app.test.js │ │ ├── razzle-build.test.js │ │ ├── razzle-start-spa.test.js │ │ └── razzle-start.test.js │ ├── examples/ │ │ └── isomorphic-examples.test.js │ ├── fixtures/ │ │ ├── build-default/ │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ └── nothing.txt │ │ │ └── src/ │ │ │ ├── client.css │ │ │ ├── client.js │ │ │ └── index.js │ │ ├── build-default-spa/ │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ ├── index.html │ │ │ │ └── nothing.txt │ │ │ ├── razzle.config.js │ │ │ └── src/ │ │ │ ├── client.css │ │ │ └── client.js │ │ ├── build-with-babelrc/ │ │ │ ├── .babelrc │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ └── nothing.txt │ │ │ └── src/ │ │ │ ├── client.css │ │ │ ├── client.js │ │ │ └── index.js │ │ ├── build-with-custom-config/ │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ └── nothing.txt │ │ │ ├── razzle.config.js │ │ │ └── src/ │ │ │ ├── client.css │ │ │ ├── client.js │ │ │ └── index.js │ │ ├── build-with-custom-config-invalid/ │ │ │ ├── package.json │ │ │ ├── public/ │ │ │ │ └── nothing.txt │ │ │ ├── razzle.config.js │ │ │ └── src/ │ │ │ ├── client.css │ │ │ ├── client.js │ │ │ └── index.js │ │ └── util.js │ ├── jest.e2e.config.json │ ├── jest.examples.config.js │ └── utils/ │ └── psKill.js └── website/ ├── .babelrc ├── .github/ │ └── CODEOWNERS ├── .gitignore ├── .nextra/ │ ├── arrow-right.js │ ├── babel-plugin-nextjs-mdx-patch.js │ ├── config.js │ ├── directories.js │ ├── docsearch.js │ ├── github-icon.js │ ├── layout.js │ ├── nextra-loader.js │ ├── nextra.js │ ├── search.js │ ├── ssg.js │ ├── styles.css │ └── theme.js ├── components/ │ ├── features.js │ ├── logo.js │ └── video.js ├── jsconfig.json ├── next.config.js ├── nextra.config.js ├── package.json ├── pages/ │ ├── _app.js │ ├── _document.js │ ├── change-log.mdx │ ├── deployment-options/ │ │ ├── aws.md │ │ ├── azure.md │ │ ├── layer0.md │ │ ├── meta.json │ │ ├── plesk.md │ │ └── vercel.md │ ├── docs/ │ │ ├── customization.md │ │ ├── environment-variables.md │ │ ├── experimental-features.md │ │ ├── how-it-works.md │ │ ├── meta.json │ │ ├── single-page-applications.md │ │ ├── static-export.md │ │ └── upgrade-guide.md │ ├── getting-started.mdx │ ├── index.mdx │ ├── meta.json │ └── plugins/ │ └── meta.json ├── postcss.config.js ├── public/ │ └── favicon/ │ └── site.webmanifest └── tailwind.config.js ================================================ FILE CONTENTS ================================================ ================================================ FILE: .all-contributorsrc ================================================ { "projectName": "razzle", "projectOwner": "jaredpalmer", "files": [ "README.md" ], "imageSize": 100, "commit": true, "contributors": [ { "login": "jaredpalmer", "name": "Jared Palmer", "avatar_url": "https://avatars2.githubusercontent.com/u/4060187?v=4", "profile": "http://jaredpalmer.com", "contributions": [ "question", "code", "design", "doc", "example", "ideas", "review", "test", "tool" ] }, { "login": "Nimaa77", "name": "Nima Arefi", "avatar_url": "https://avatars1.githubusercontent.com/u/49443619?v=4", "profile": "https://github.com/Nimaa77", "contributions": [ "question", "code", "doc", "example", "ideas", "review", "test", "tool" ] }, { "login": "fivethreeo", "name": "Øyvind Saltvik", "avatar_url": "https://avatars2.githubusercontent.com/u/410?v=4", "profile": "https://github.com/fivethreeo/", "contributions": [ "question", "code", "example", "ideas", "review", "test", "tool" ] }, { "login": "jariz", "name": "Jari Zwarts", "avatar_url": "https://avatars3.githubusercontent.com/u/1415847?v=4", "profile": "https://jari.io", "contributions": [ "question", "code", "ideas", "plugin", "review" ] }, { "login": "gaearon", "name": "Dan Abramov", "avatar_url": "https://avatars0.githubusercontent.com/u/810438?v=4", "profile": "http://twitter.com/dan_abramov", "contributions": [ "code", "ideas" ] }, { "login": "ericclemmons", "name": "Eric Clemmons", "avatar_url": "https://avatars0.githubusercontent.com/u/15182?v=4", "profile": "http://ericclemmons.github.com/", "contributions": [ "code", "ideas" ] }, { "login": "HofmannZ", "name": "Zino Hofmann", "avatar_url": "https://avatars3.githubusercontent.com/u/17142193?v=4", "profile": "https://www.linkedin.com/in/zinohofmann/", "contributions": [ "example" ] }, { "login": "lucasterra", "name": "Lucas Terra", "avatar_url": "https://avatars2.githubusercontent.com/u/441058?v=4", "profile": "https://www.linkedin.com/in/lucasterra7/", "contributions": [ "code", "example", "plugin" ] }, { "login": "rayandrews", "name": "Ray Andrew", "avatar_url": "https://avatars1.githubusercontent.com/u/4437323?v=4", "profile": "https://www.linkedin.com/in/ray-andrew/", "contributions": [ "code", "example", "plugin" ] }, { "login": "heithemmoumni", "name": "Heithem Moumni", "avatar_url": "https://avatars0.githubusercontent.com/u/18581851?v=4", "profile": "https://www.linkedin.com/in/heithemmoumni/", "contributions": [ "code", "example", "plugin" ] }, { "login": "silviubogan", "name": "Silviu Bogan", "avatar_url": "https://avatars.githubusercontent.com/u/198924?v=4", "profile": "https://silviubogan.ro/", "contributions": [ "code", "example" ] } ], "repoType": "github", "commitConvention": "none" } ================================================ FILE: .changeset/config.json ================================================ { "commit": false, "updateInternalDependencies": "minor", "linked": [], "fixed": [["babel-preset-razzle","create-razzle-app","razzle", "razzle-*"]], "access": "public", "baseBranch": "master", "ignore": [], "changelog": ["@changesets/changelog-github", { "repo": "jaredpalmer/razzle" }] } ================================================ FILE: .eslintignore ================================================ node_modules/ build my-app* test/fixtures test/tests packages/create-razzle-app/templates examples ================================================ FILE: .eslintrc ================================================ { "extends": "eslint:recommended", "env": { "browser": true, "commonjs": true, "node": true, "es6": false }, "parserOptions": { "ecmaVersion": 6 }, "rules": { "no-console": "off", "strict": ["error", "global"], "curly": "warn" } } ================================================ FILE: .github/CODE_OF_CONDUCT.md ================================================ # Contributor Covenant Code of Conduct - [Contributor Covenant Code of Conduct](#contributor-covenant-code-of-conduct) - [Our Pledge](#our-pledge) - [Our Standards](#our-standards) - [Our Responsibilities](#our-responsibilities) - [Scope](#scope) - [Enforcement](#enforcement) - [Attribution](#attribution) ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at [info@palmer.net](mailto:info@palmer.net). All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ ================================================ FILE: .github/CONTRIBUTING.md ================================================ # Contributing to Razzle Hi there! Thanks for your interest in Razzle. This guide will help you get started contributing. - [Contributing to Razzle](#contributing-to-razzle) - [Developing locally](#developing-locally) - [optionally install add-dependencies](#optionally-install-add-dependencies) - [Commands](#commands) - [Workflow for working on razzle core with examples](#workflow-for-working-on-razzle-core-with-examples) - [or](#or) - [git checkout -b my-feature-branch master](#git-checkout--b-my-feature-branch-master) - [git checkout -b my-feature-branch three](#git-checkout--b-my-feature-branch-three) - [/home/oyvind/Documents/GitHub/razzle/](#homeoyvinddocumentsgithubrazzle) - [to make sure tests pass](#to-make-sure-tests-pass) - [to add a new example](#to-add-a-new-example) - [to work on a example](#to-work-on-a-example) - [if it is a example with webpack5 you need to do](#if-it-is-a-example-with-webpack5-you-need-to-do) - [switch back to webpack4 later to work with webpack4](#switch-back-to-webpack4-later-to-work-with-webpack4) - [then](#then) - [if you want to add dependencies to the example](#if-you-want-to-add-dependencies-to-the-example) - [if you make changes to startserver plugin](#if-you-make-changes-to-startserver-plugin) - [to run example tests with unreleased razzle packages with specific webpack and specific tests](#to-run-example-tests-with-unreleased-razzle-packages-with-specific-webpack-and-specific-tests) - [Commands being run during testing puts output and puppeteer screenshots in test-artifacts/](#commands-being-run-during-testing-puts-output-and-puppeteer-screenshots-in-test-artifacts) - [Trouble with puppeteer?](#trouble-with-puppeteer) - [Updating your fork](#updating-your-fork) - [Adding examples](#adding-examples) - [Use examples/basic as template](#use-examplesbasic-as-template) - [Naming examples](#naming-examples) - [How to get your example merged](#how-to-get-your-example-merged) - [Guidelines](#guidelines) - [Why wasn't my PR merged?](#why-wasnt-my-pr-merged) - [Getting recognition](#getting-recognition) - [Getting help](#getting-help) Razzle is monorepo made up of a several npm packages powered by Lerna. - `examples`: All examples go in here. - `packages`: This is where the magic happens - `babel-preset-razzle`: Razzle's default Babel preset. - `create-razzle-app`: Razzle's CLI tool responsible for initialization of new projects - `razzle`: The core library - `razzle-dev-utils`: Utilities and helpers - `scripts`: Utility scripts related to cleaning and bootstrapping the repo - `test`: End-to-end tests ## Developing locally First, fork the repo to your GitHub account. Then clone your fork to your local machine and make a new branch for your feature/bug/patch etc. It's a good idea to not develop directly on master so you can get updates. ``` git clone https://github.com//razzle.git cd razzle git checkout -B NODE_ENV=development yarn install ---ignore-engines # optionally install add-dependencies sudo npm install add-dependencies -g ``` This will install all `node_modules` in all the packages and symlink inter-dependencies. Thus when you make local changes in any of the packages you can try them immediately in all the examples. `add-dependencies` can be used to just add packages to `package.json`. ### Commands - `yarn clean`: Clean up all `node_modules` and remove all symlinks from packages and examples. - `yarn test --runInBand`: Runs all tests - `yarn test:packages`: Runs tests for packages - `yarn test:e2e`: Runs end-to-end tests - `yarn build-docs`: Builds docs/ updates doc TOC - `yarn publish-all-canary`: Does a `razzle@canary` release. - `yarn publish-all-stable`: Does a a stable release(uses the npm version released of the packages) - `yarn new-example`: Creates a new example from another example. `yarn new-example basic new-example`. - `yarn bootstrap-examples`: Run `yarn` with specific examples as workspaces. Automatically symlinks inter-dependent modules. Run `yarn restrap` in the example to reinstall. - `yarn test:examples:simple`: Runs tests for all simple examples (uses the npm version released of the packages) - `yarn test:examples:complex`: Runs tests for all complex examples (uses the npm version released of the packages) - `yarn test:examples`: Runs tests for all examples (uses the npm version released of the packages) ### Workflow for working on razzle core with examples ```bash git clone https://github.com//razzle.git cd razzle git checkout -b my-feature-branch canary # or # git checkout -b my-feature-branch master # git checkout -b my-feature-branch three sudo npm install add-dependencies yalc -g pwd # /home/oyvind/Documents/GitHub/razzle/ NODE_ENV=development yarn install ---ignore-engines # to make sure tests pass yarn test --runInBand # to add a new example yarn new-example existingexample with-somefeature # to work on a example cd examples/basic example="$(basename $PWD)" pushd ../.. # if it is a example with webpack5 you need to do yarn add -W webpack@5.24.0 html-webpack-plugin@5.2.0 # switch back to webpack4 later to work with webpack4 yarn add -W webpack@4.46.0 html-webpack-plugin@4.5.2 # then yarn bootstrap-examples $example popd yarn build # if you want to add dependencies to the example add-dependencies somedependency yarn restrap # if you make changes to startserver plugin pushd ../.. cd packages/razzle-start-server-webpack-plugin yarn build popd # to run example tests with unreleased razzle packages with specific webpack and specific tests WEBPACK_DEPS="webpack@5.24.0 html-webpack-plugin@5.2.0" PACKAGE_MANAGER="yalc" NPM_TAG="development" yarn test:examples --runInBand -t with-tailwindcss WEBPACK_DEPS="webpack@4.46.0 html-webpack-plugin@4.5.2" PACKAGE_MANAGER="yalc" NPM_TAG="development" yarn test:examples --runInBand -t with-tailwindcss # Commands being run during testing puts output and puppeteer screenshots in test-artifacts/ # Trouble with puppeteer? sudo sysctl -w kernel.unprivileged_userns_clone=1 ``` ### Updating your fork When you want to pull down changes to your fork enter the following into your terminal: ```bash git checkout master git pull origin master ``` ## Adding examples ### Use examples/basic as template If you'd like to add an example, I suggest you duplicate the `examples/basic` folder `yarn new-example basic your-example`and use that as kind of base template. Before you start adding stuff, go ahead and change the name of the package in the your new example's `package.json`. Then go back to the project root and run `yarn bootstrap-examples your-example`. This will make sure that your new example is using your local version of all the `packages`. ### Naming examples All example folders should be named `with-`. Each example's npm package name (found in it's `package.json`) should look like `razzle-examples-with-`. ### How to get your example merged - Make sure to comment the important parts of your code and include a **well-written** "Idea behind the example" section. This is more important to me than your actual code. - Keep your example limited to one idea / library / feature (e.g. don't submit `with-styled-components-and-material-ui`). That being said, there are times when this rule will be relaxed such as if you are showing how to use Apollo and Redux or \ + React Router. - Your example **MUST** implement Hot Module Replacement. If it does not update when you make edits, you have broken something. - Your example should be minimalistic and concise, or a direct copy of another prominent example from the original library (like copying an example directly from react-redux). ### Guidelines [Commit message guidelines](https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-commit-message-guidelines) ## Why wasn't my PR merged? I will do my best to write out my reasoning before closing a PR, but 80% of the time it falls under one of these... - You did not read this document - Your code breaks an internal application (I will be transparent about this) - Your code conflicts with some future plans (I will be transparent about this too) - You've said something inappropriate or have broken the Code of Conduct ## Getting recognition We use the project README to recognize the contributions of members of the project community. To add a contributor: `all-contributors add github_username doc,code` [Valid contributing keys](https://allcontributors.org/docs/en/emoji-key) ## Getting help Tweet / DM [@jaredpalmer](https://twitter.com/jaredpalmer) Tweet / DM [@nima_arf](https://twitter.com/nima_arf) Tweet / DM [@fivethreeo](https://twitter.com/fivethreeo) ================================================ FILE: .github/FUNDING.yml ================================================ # These are supported funding model platforms open_collective: razzle ================================================ FILE: .github/ISSUE_TEMPLATE/Bug_report.md ================================================ --- name: "\U0001F41B Bug report" about: Create a report to help make Razzle better --- ## 🐛 Bug report ### Current Behavior ### Expected behavior ### Reproducible example ### Suggested solution(s) ### Additional context ### Your environment | Software | Version(s) | | ---------------- | ---------- | | Razzle | | Razzle Plugins | | Node | | Browser | | npm/Yarn | | Operating System | | TypeScript | | React | ================================================ FILE: .github/ISSUE_TEMPLATE/Documentation.md ================================================ --- name: "\U0001F41B Documentation" about: Imrovements or suggestions of Razzle documentation --- ## 📖 Documentation ================================================ FILE: .github/ISSUE_TEMPLATE/Feature_request.md ================================================ --- name: "\U0001F680Feature request" about: Suggest an idea for Razzle --- ## 🚀 Feature request ### Current Behavior ### Desired Behavior ### Suggested Solution ### Who does this impact? Who is this for? ### Describe alternatives you've considered ### Additional context ================================================ FILE: .github/ISSUE_TEMPLATE/Question.md ================================================ --- name: "❓Question" about: 'Ask a Question!' --- ## ❓Question ================================================ FILE: .github/labels.yml ================================================ examples: - examples/* - examples/**/* razzle: - packages/razzle/* - packages/razzle/**/* webpack: - packages/razzle/* - packages/razzle/**/* plugins: - packages/razzle-plugin-*/* - packages/razzle-plugin-*/**/* repo: - ./* ================================================ FILE: .github/stale.yml ================================================ # Number of days of inactivity before an issue becomes stale daysUntilStale: 60 # Number of days of inactivity before a stale issue is closed daysUntilClose: 14 # Issues with these labels will never be considered stale exemptLabels: - pinned - security # Label to use when marking an issue as stale staleLabel: stale # Comment to post when marking an issue as stale. Set to `false` to disable markComment: false # Comment to post when closing a stale issue. Set to `false` to disable closeComment: Hi everyone, in an effort to clean up the issue list, this issue was closed due to inactivity. If this is still related / important to you please tag me: @ elliottjro. Thanks for understanding! ================================================ FILE: .github/workflows/examples.yml ================================================ name: Test examples on trigger on: workflow_dispatch: inputs: npm_tag: description: 'The npm tag for create razzle app' default: 'development' jest_filter: description: 'The filter for jest tests' default: 'simple' package_manager: description: 'The package manager to use, yalc with yarn default' default: 'yalc' jobs: build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: node-version: [10.x, 12.x, 13.x, 14.x] os: [ubuntu-latest, windows-latest, macOS-latest] webpack: ["webpack@4.46.0 html-webpack-plugin@4.5.2" , "webpack@5.24.0 html-webpack-plugin@5.2.0"] name: Test on node ${{ matrix.node-version }} and ${{ matrix.os }} with ${{ matrix.webpack }} steps: - name: Get current date id: date run: echo "::set-output name=date::$(date +'%Y-%m-%dT%H:%M:%S')" - name: Log date run: echo "${{ steps.date.outputs.date }}" - name: Set default run status run: echo "::set-output name=last_run_status::default" > last_run_status - name: Restore last run status id: last_run uses: actions/cache@v2 with: path: | last_run_status key: ${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}-${{ steps.date.outputs.date }} restore-keys: | ${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}- - name: Set last run status id: last_run_status run: cat last_run_status - name: Checkout ref uses: actions/checkout@v2 with: ref: ${{ github.event.workflow_dispatch.ref }} - name: Use Node.js ${{ matrix.node-version }} if: steps.last_run_status.outputs.last_run_status != 'success' uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - name: Install yalc globally if: steps.last_run_status.outputs.last_run_status != 'success' run: npm install -g yalc - name: Install elm globally if: steps.last_run_status.outputs.last_run_status != 'success' run: yarn global add elm - name: Restore lerna if: steps.last_run_status.outputs.last_run_status != 'success' id: cache uses: actions/cache@v2 with: path: | node_modules */*/node_modules key: ${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}-${{ hashFiles('**/yarn.lock') }} - name: Install and bootstrap packages if: steps.cache.outputs.cache-hit != 'true' && steps.last_run_status.outputs.last_run_status != 'success' run: yarn install --frozen-lockfile --ignore-engines --network-timeout 1000000 - name: Install ${{ matrix.webpack }} if: steps.cache.outputs.cache-hit != 'true' && steps.last_run_status.outputs.last_run_status != 'success' run: yarn add -WD ${{ matrix.webpack }} --ignore-engines --network-timeout 1000000 - name: Run tests id: test_run if: steps.last_run_status.outputs.last_run_status != 'success' run: yarn test:examples -t ${{ github.event.inputs.jest_filter }} --runInBand env: WEBPACK_DEPS: "${{ matrix.webpack }}" NPM_TAG: "${{ github.event.inputs.npm_tag }}" PACKAGE_MANAGER: "${{ github.event.inputs.package_manager }}" WARNINGS_ERRORS_DISABLE: true - name: Upload test artifacts uses: actions/upload-artifact@v2 if: ${{ always() && steps.last_run_status.outputs.last_run_status != 'success' }} with: name: ${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}-${{ github.event.inputs.npm_tag }}-${{ github.event.inputs.jest_filter }}-${{ github.event.inputs.package_manager }} path: test-artifacts/ - name: Save run status if: steps.last_run_status.outputs.last_run_status != 'success' run: echo "::set-output name=last_run_status::${{ steps.test_run.outcome }}" > last_run_status ================================================ FILE: .github/workflows/examples_node14.yml ================================================ name: Test examples on trigger using node 14.x on: workflow_dispatch: inputs: npm_tag: description: 'The npm tag for create razzle app' default: 'development' jest_filter: description: 'The filter for jest tests' default: 'simple' package_manager: description: 'The package manager to use, yalc with yarn default' default: 'yalc' jobs: build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: node-version: [14.x] os: [ubuntu-latest, windows-latest, macOS-latest] webpack: ["webpack@4.46.0 html-webpack-plugin@4.5.2" , "webpack@5.24.0 html-webpack-plugin@5.2.0"] name: Test on node ${{ matrix.node-version }} and ${{ matrix.os }} with ${{ matrix.webpack }} steps: - name: Get current date id: date run: echo "::set-output name=date::$(date +'%Y-%m-%dT%H:%M:%S')" - name: Log date run: echo "${{ steps.date.outputs.date }}" - name: Set default run status run: echo "::set-output name=last_run_status::default" > last_run_status - name: Restore last run status id: last_run uses: actions/cache@v2 with: path: | last_run_status key: ${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}-${{ steps.date.outputs.date }} restore-keys: | ${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}- - name: Set last run status id: last_run_status run: cat last_run_status - name: Checkout ref uses: actions/checkout@v2 with: ref: ${{ github.event.workflow_dispatch.ref }} - name: Use Node.js ${{ matrix.node-version }} if: steps.last_run_status.outputs.last_run_status != 'success' uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - name: Install yalc globally if: steps.last_run_status.outputs.last_run_status != 'success' run: npm install -g yalc - name: Install elm globally if: steps.last_run_status.outputs.last_run_status != 'success' run: yarn global add elm - name: Restore lerna if: steps.last_run_status.outputs.last_run_status != 'success' id: cache uses: actions/cache@v2 with: path: | node_modules */*/node_modules key: ${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}-${{ hashFiles('**/yarn.lock') }} - name: Install and bootstrap packages if: steps.cache.outputs.cache-hit != 'true' && steps.last_run_status.outputs.last_run_status != 'success' run: yarn install --frozen-lockfile --ignore-engines --network-timeout 1000000 - name: Install ${{ matrix.webpack }} if: steps.cache.outputs.cache-hit != 'true' && steps.last_run_status.outputs.last_run_status != 'success' run: yarn add -WD ${{ matrix.webpack }} --ignore-engines --network-timeout 1000000 - name: Run tests id: test_run if: steps.last_run_status.outputs.last_run_status != 'success' run: yarn test:examples -t ${{ github.event.inputs.jest_filter }} --runInBand env: WEBPACK_DEPS: "${{ matrix.webpack }}" NPM_TAG: "${{ github.event.inputs.npm_tag }}" PACKAGE_MANAGER: "${{ github.event.inputs.package_manager }}" WARNINGS_ERRORS_DISABLE: true - name: Upload test artifacts uses: actions/upload-artifact@v2 if: ${{ always() && steps.last_run_status.outputs.last_run_status != 'success' }} with: name: ${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}-${{ github.event.inputs.npm_tag }}-${{ github.event.inputs.jest_filter }}-${{ github.event.inputs.package_manager }} path: test-artifacts/ - name: Save run status if: steps.last_run_status.outputs.last_run_status != 'success' run: echo "::set-output name=last_run_status::${{ steps.test_run.outcome }}" > last_run_status ================================================ FILE: .github/workflows/label.yml ================================================ # Automatically label PRs every hour based on your .github/labels.yaml: # # This workflow will triage pull requests and apply a label based on the # paths that are modified in the pull request. # # To use this workflow, you will need to set up a .github/labeler.yml # file with configuration. For more information, see: # https://github.com/actions/labeler/blob/master/README.md name: "Label PRs from globs" on: schedule: - cron: "0 1 * * *" jobs: execute: runs-on: ubuntu-latest steps: - name: Label PRs uses: jpmcb/prow-github-actions@v1.0.0 with: jobs: 'pr-labeler' github-token: "${{ secrets.GITHUB_TOKEN }}" ================================================ FILE: .github/workflows/nodejs.yml ================================================ name: Run tests on push on: [push] jobs: build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: node-version: [10.x, 12.x, 13.x, 14.x] os: [ubuntu-latest, windows-latest, macOS-latest] webpack: ["webpack@4.46.0 html-webpack-plugin@4.5.2" , "webpack@5.24.0 html-webpack-plugin@5.2.0"] name: Test on node ${{ matrix.node-version }} and ${{ matrix.os }} with ${{ matrix.webpack }} steps: - name: Get current date id: date run: echo "::set-output name=date::$(date +'%Y-%m-%dT%H:%M:%S')" - name: Log date run: echo "${{ steps.date.outputs.date }}" - name: Set default run status run: echo "::set-output name=last_run_status::default" > last_run_status - name: Restore last run status id: last_run uses: actions/cache@v2 with: path: | last_run_status key: ${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}-${{ steps.date.outputs.date }} restore-keys: | ${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}- - name: Set last run status id: last_run_status run: cat last_run_status - name: Log last run status run: echo "${{ steps.last_run_status.outputs.last_run_status }}" - uses: actions/checkout@v1 if: steps.last_run_status.outputs.last_run_status != 'success' - name: Use Node.js ${{ matrix.node-version }} if: steps.last_run_status.outputs.last_run_status != 'success' uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - name: Install elm globally if: steps.last_run_status.outputs.last_run_status != 'success' run: yarn global add elm - name: Restore lerna id: cache if: steps.last_run_status.outputs.last_run_status != 'success' uses: actions/cache@v2 with: path: | node_modules */*/node_modules key: ${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}-${{ hashFiles('**/yarn.lock') }} - name: Install and bootstrap packages if: steps.cache.outputs.cache-hit != 'true' && steps.last_run_status.outputs.last_run_status != 'success' run: yarn install --frozen-lockfile --ignore-engines --network-timeout 1000000 - name: Install ${{ matrix.webpack }} if: steps.cache.outputs.cache-hit != 'true' && steps.last_run_status.outputs.last_run_status != 'success' run: yarn add -WD ${{ matrix.webpack }} --ignore-engines --network-timeout 1000000 - name: Run tests id: test_run if: steps.last_run_status.outputs.last_run_status != 'success' run: yarn test --runInBand --coverage env: CI: true WARNINGS_ERRORS_DISABLE: true - name: Save run status if: steps.last_run_status.outputs.last_run_status != 'success' run: echo "::set-output name=last_run_status::${{ steps.test_run.outcome }}" > last_run_status ================================================ FILE: .github/workflows/release.yml ================================================ name: Release on: push: branches: - master jobs: release: name: Release runs-on: ubuntu-latest steps: - name: Checkout Repo uses: actions/checkout@v2 with: # This makes Actions fetch all Git history so that Changesets can generate changelogs with the correct commits fetch-depth: 0 - name: Setup Node.js 12.x uses: actions/setup-node@v2 with: node-version: 12.x - name: Install Dependencies run: yarn --frozen-lockfile - name: Create Release Pull Request or Publish uses: changesets/action@master with: publish: yarn changeset publish env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} NPM_TOKEN: ${{ secrets.NPM_TOKEN }} ================================================ FILE: .github/workflows/test-examples.yml ================================================ name: Test examples on trigger on: workflow_dispatch: inputs: logLevel: description: 'Log level' required: true default: 'warning' tags: description: 'Test scenario tags' jobs: build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: node-version: [8.x, 10.x, 12.x, 13.x, 14.x] os: [ubuntu-latest, windows-latest, macOS-latest] webpack: ["webpack@4.46.0 html-webpack-plugin@4.5.2" , "webpack@5.24.0 html-webpack-plugin@5.2.0"] name: Test on node ${{ matrix.node-version }} and ${{ matrix.os }} with ${{ matrix.webpack }} steps: - name: Get current date id: date run: echo "::set-output name=date::$(date +'%Y-%m-%dT%H:%M:%S')" - name: Log date run: echo "${{ steps.date.outputs.date }}" - name: Set default run status run: echo "::set-output name=last_run_status::default" > last_run_status - name: Restore last run status id: last_run uses: actions/cache@v2 with: path: | last_run_status key: ${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}-${{ steps.date.outputs.date }} restore-keys: | ${{ github.run_id }}-${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}- - name: Set last run status id: last_run_status run: cat last_run_status - name: Log last run status run: echo "${{ steps.last_run_status.outputs.last_run_status }}" - uses: actions/checkout@v1 if: steps.last_run_status.outputs.last_run_status != 'success' - name: Use Node.js ${{ matrix.node-version }} if: steps.last_run_status.outputs.last_run_status != 'success' uses: actions/setup-node@v1 with: node-version: ${{ matrix.node-version }} - name: Install elm globally if: steps.last_run_status.outputs.last_run_status != 'success' run: yarn global add elm - name: Restore lerna id: cache if: steps.last_run_status.outputs.last_run_status != 'success' uses: actions/cache@v2 with: path: | node_modules */*/node_modules key: ${{ matrix.os }}-${{ matrix.node-version }}-${{ matrix.webpack }}-${{ hashFiles('**/yarn.lock') }} - name: Install and bootstrap packages if: steps.cache.outputs.cache-hit != 'true' && steps.last_run_status.outputs.last_run_status != 'success' run: yarn install --frozen-lockfile --ignore-engines --network-timeout 1000000 - name: Install ${{ matrix.webpack }} if: steps.cache.outputs.cache-hit != 'true' && steps.last_run_status.outputs.last_run_status != 'success' run: yarn add -WD ${{ matrix.webpack }} --ignore-engines --network-timeout 1000000 - name: Run tests id: test_run if: steps.last_run_status.outputs.last_run_status != 'success' run: yarn test --runInBand --coverage env: CI: true WARNINGS_ERRORS_DISABLE: true - name: Save run status if: steps.last_run_status.outputs.last_run_status != 'success' run: echo "::set-output name=last_run_status::${{ steps.test_run.outcome }}" > last_run_status ================================================ FILE: .gitignore ================================================ # Logs logs *.log npm-debug.log* .DS_Store stage-* example/ # Runtime data pids *.pid *.seed test-artifacts examples/*/cache examples/*/build *.sqlite3 # Directory for instrumented libs generated by jscoverage/JSCover lib-cov # Coverage directory used by tools like istanbul coverage # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) .grunt .yarn # node-waf configuration .lock-wscript # Dependency directory node_modules # Optional npm cache directory .npm # Optional REPL history .node_repl_history # Build Output build .vscode # Editors **/.idea .vercel ================================================ FILE: .prettierrc ================================================ { "trailingComma": "es5", "singleQuote": true, "semi": true } ================================================ FILE: LICENSE ================================================ The MIT License (MIT) Copyright (c) 2016 Jared Palmer Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. ================================================ FILE: examples/.gitignore ================================================ yarn.lock package-lock.json ================================================ FILE: examples/basic/README.md ================================================ # Razzle Basic Example ## How to use Create and start the example: ```bash npx create-razzle-app --example basic basic cd basic yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle. It satisfies the entry points `src/index.js` for the server and and `src/client.js` for the browser. ================================================ FILE: examples/basic/gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/basic/package.json ================================================ { "name": "razzle-examples-basic", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/basic/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/basic/sandbox.config.json ================================================ { "container": { "port": 3000 } } ================================================ FILE: examples/basic/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/basic/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/basic/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/basic/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/basic/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/basic/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/basic-server/README.md ================================================ # Razzle Basic Server Example ## How to use Create and start the example: ```bash npx create-razzle-app --example basic-server basic-server cd basic-server yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle. It satisfies the entry point `src/index.js` for the server. ================================================ FILE: examples/basic-server/gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/basic-server/package.json ================================================ { "name": "razzle-examples-basic-server", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/basic-server/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/basic-server/razzle.config.js ================================================ 'use strict'; module.exports = { options: { buildType: 'server-only', } }; ================================================ FILE: examples/basic-server/sandbox.config.json ================================================ { "container": { "port": 3000 } } ================================================ FILE: examples/basic-server/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/basic-server/src/App.js ================================================ import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/basic-server/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/basic-server/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/basic-server/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle
${markup}
`; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/basic-serverless/README.md ================================================ # Razzle Basic Example ## How to use Create and start the example: ```bash npx create-razzle-app --example basic basic cd basic yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle. It satisfies the entry points `src/index.js` for the server and and `src/client.js` for the browser. ================================================ FILE: examples/basic-serverless/gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/basic-serverless/package.json ================================================ { "name": "razzle-examples-basic-serverless", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "ejs": "^3.1.6", "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "babel-preset-razzle": "4.2.15", "html-webpack-plugin": "^4.5.2", "mini-css-extract-plugin": "^0.9.0", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/basic-serverless/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/basic-serverless/razzle.config.js ================================================ 'use strict'; const path = require('path'); module.exports = { options: { buildType: 'iso-serverless' }, modifyWebpackConfig(opts) { const config = opts.webpackConfig; if (opts.env.target === 'node') { config.plugins.push( new opts.webpackObject.ContextReplacementPlugin( // we want to replace context /express\/lib/, // and replace all searches in // express/lib/* path.resolve('node_modules'), // to look in folder 'node_modules' { // and return a map 'ejs': 'ejs' // which resolves request for 'ejs' } // to module 'ejs' ) // __webpack_require__(...)(mod) // we set `mod = 'ejs'` ) } return config; } }; ================================================ FILE: examples/basic-serverless/sandbox.config.json ================================================ { "container": { "port": 3000 } } ================================================ FILE: examples/basic-serverless/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/basic-serverless/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/basic-serverless/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/basic-serverless/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/basic-serverless/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/basic-serverless/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/basic-spa/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/basic-spa/README.md ================================================ # Razzle Single Page App Example ## How to use Create and start the example: ```bash npx create-razzle-app --example basic-spa basic-spa cd basic-spa yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle to build a single page application (instead of a universal/isomorphic application). It satisfies the entry point `src/client.js` for the browser and includes a template HTML file in `public/index.html`. ================================================ FILE: examples/basic-spa/package.json ================================================ { "name": "razzle-examples-basic-spa", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "serve -s build/public" }, "dependencies": { "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "babel-preset-razzle": "4.2.15", "html-webpack-plugin": "5.2.0", "mini-css-extract-plugin": "^0.9.0", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "serve": "^11.3.2", "webpack": "5.24.0", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/basic-spa/public/index.html ================================================ <%= htmlWebpackPlugin.tags.headTags %> React App
<%= htmlWebpackPlugin.tags.bodyTags %> ================================================ FILE: examples/basic-spa/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/basic-spa/razzle.config.js ================================================ 'use strict'; module.exports = { options: { buildType: 'single-page-application', } }; ================================================ FILE: examples/basic-spa/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/basic-spa/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/basic-spa/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/basic-spa/src/client.js ================================================ import React from 'react'; import { render } from 'react-dom'; import App from './App'; render(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-afterjs/README.md ================================================ # with-afterjs example This example have been moved here: [jaredpalmer/after.js](https://github.com/jaredpalmer/after.js/blob/master/examples/basic) ================================================ FILE: examples/with-custom-babel-config/.babelrc ================================================ { "presets": [ "razzle/babel" ], "plugins": [ "@babel/plugin-proposal-do-expressions" ] } ================================================ FILE: examples/with-custom-babel-config/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-custom-babel-config/README.md ================================================ # Razzle Custom Babel Configuration Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-custom-babel-config with-custom-babel-config cd with-custom-babel-config yarn start ``` ## Idea behind the example This is an example of how to extend Razzle with a custom `.babelrc` file. ================================================ FILE: examples/with-custom-babel-config/package.json ================================================ { "name": "razzle-examples-with-custom-babel-config", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1", "react-router-dom": "^5.1.2", "serialize-javascript": "^3.0.0" }, "devDependencies": { "@babel/core": "^7.12.10", "@babel/plugin-proposal-do-expressions": "^7.8.3", "babel-preset-razzle": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-custom-babel-config/razzle.config.js ================================================ module.exports = { options: { verbose: true }, } ================================================ FILE: examples/with-custom-babel-config/src/App.js ================================================ import React from 'react'; import { Route, Switch } from 'react-router-dom'; import Home from './Home'; const App = () => ( ); export default App; ================================================ FILE: examples/with-custom-babel-config/src/Home.js ================================================ import React from "react"; export default class MyLuckNo extends React.Component { state = { randomNo: null }; componentDidMount() { this.recalculate(); } recalculate() { this.setState({ randomNo: Math.ceil(Math.random() * 100), }); } render() { const { randomNo } = this.state; if (randomNo === null) { return

Please wait..

; } // This is an experimental JavaScript feature where we can get with // using babel-preset-stage-0 const message = do { if (randomNo < 30) { // eslint-disable-next-line no-unused-expressions ("Do not give up. Try again."); } else if (randomNo < 60) { // eslint-disable-next-line no-unused-expressions ("You are a lucky guy"); } else { // eslint-disable-next-line no-unused-expressions ("You are soooo lucky!"); } }; return (

Your Lucky number is: "{randomNo}"

{message}

); } } ================================================ FILE: examples/with-custom-babel-config/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; import App from './App'; hydrate( , document.getElementById('root') ); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-custom-babel-config/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-custom-babel-config/src/server.js ================================================ import { StaticRouter } from 'react-router-dom'; import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const context = {}; const markup = renderToString( ); if (context.url) { return { redirect: context.url }; } else { const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; } }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html = '', redirect = false } = renderApp(req, res); if (redirect) { res.redirect(redirect); } else { res.send(html); } }); export default server; ================================================ FILE: examples/with-custom-devserver-options/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-custom-devserver-options/README.md ================================================ # Razzle Custom Webpack Configuration Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-custom-devserver-options with-custom-devserver-options cd with-custom-devserver-options yarn start ``` ## Idea behind the example This example demonstrates how to use a `razzle.config.js` file to modify Razzle's underlying webpack devServer configuration. It modifies the port of the devServer in dev (`razzle start`). Note that this file is not transpiled, and so you must write it with vanilla Node.js-compatible JavaScript. ```js // razzle.config.js 'use strict'; module.exports = { modifyWebpackConfig(opts) { const config = opts.webpackConfig; if (opts.env.target === 'web' && opts.env.dev) { config.devServer.port = 3002; // If behind a proxy on a public domain // config.devServer.public = 'example.com:8080'; } return config; }, }; ``` ================================================ FILE: examples/with-custom-devserver-options/package.json ================================================ { "name": "razzle-examples-with-custom-devserver-options", "version": "4.2.15", "license": "MIT", "scripts": { "start": "cross-env CLIENT_PUBLIC_PATH=http://localhost:3002/ razzle start", "start:proxied": "cross-env CLIENT_PUBLIC_PATH=http://example.com:8080/ razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "cross-env": "^7.0.3", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-custom-devserver-options/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-custom-devserver-options/razzle.config.js ================================================ 'use strict'; module.exports = { modifyWebpackConfig(opts) { const config = opts.webpackConfig; if (opts.env.target === 'web' && opts.env.dev) { config.devServer.port = 3002; // If behind a proxy on a public domain // config.devServer.public = 'example.com:8080'; } return config; }, }; ================================================ FILE: examples/with-custom-devserver-options/src/App.js ================================================ import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-custom-devserver-options/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-custom-devserver-options/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-custom-devserver-options/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-custom-environment-variables/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-custom-environment-variables/README.md ================================================ # Razzle Custom Environment Variables Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-custom-environment-variables with-custom-environment-variables cd with-custom-environment-variables yarn start ``` ## Idea behind the example This example shows how you can use `.env` files to set environment-specific **build-time** variables. > Note: Razzle's `.env` setup is alsmost identically to [here](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md#adding-custom-environment-variables). ```bash # .env HOST=10.69.107.189 # HOST sets the host IP address PORT=4000 # Serve on :4000 VERBOSE=true # Show verbose logging output (will not clear console between compiles) RAZZLE_MY_CUSTOM_VARIABLE=XXXXXX # Will be available on server and client as process.env.RAZZLE_MY_CUSTOM_VARIABLE ``` ================================================ FILE: examples/with-custom-environment-variables/package.json ================================================ { "name": "razzle-examples-with-custom-environment-variables", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" }, "razzle_meta": { "port": "4000" } } ================================================ FILE: examples/with-custom-environment-variables/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-custom-environment-variables/src/App.js ================================================ import React from 'react'; const App = () =>
{process.env.RAZZLE_CUSTOM_VAR}
; export default App; ================================================ FILE: examples/with-custom-environment-variables/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-custom-environment-variables/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-custom-environment-variables/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-custom-target-babel-config/.babelrc.node ================================================ { "presets": [ "razzle/babel" ], "plugins": [ "@babel/plugin-proposal-do-expressions" ] } ================================================ FILE: examples/with-custom-target-babel-config/.babelrc.web ================================================ { "presets": [ "razzle/babel" ], "plugins": [ "@babel/plugin-proposal-do-expressions" ] } ================================================ FILE: examples/with-custom-target-babel-config/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-custom-target-babel-config/README.md ================================================ # Razzle Custom Target Babel Configuration Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-custom-target-babel-config with-custom-target-babel-config cd with-custom-target-babel-config yarn start ``` ## Idea behind the example This is an example of how to extend Razzle with a custom `.babelrc.node` and a `.babelrc.web` file. ================================================ FILE: examples/with-custom-target-babel-config/package.json ================================================ { "name": "razzle-examples-with-custom-target-babel-config", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1", "react-router-dom": "^5.1.2", "serialize-javascript": "^3.0.0" }, "devDependencies": { "@babel/core": "^7.12.10", "@babel/plugin-proposal-do-expressions": "^7.8.3", "babel-preset-razzle": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-custom-target-babel-config/razzle.config.js ================================================ module.exports = { options: { verbose: true, enableTargetBabelrc: true }, } ================================================ FILE: examples/with-custom-target-babel-config/src/App.js ================================================ import React from 'react'; import { Route, Switch } from 'react-router-dom'; import Home from './Home'; const App = () => ( ); export default App; ================================================ FILE: examples/with-custom-target-babel-config/src/Home.js ================================================ import React from "react"; export default class MyLuckNo extends React.Component { state = { randomNo: null }; componentDidMount() { this.recalculate(); } recalculate() { this.setState({ randomNo: Math.ceil(Math.random() * 100), }); } render() { const { randomNo } = this.state; if (randomNo === null) { return

Please wait..

; } // This is an experimental JavaScript feature where we can get with // using babel-preset-stage-0 const message = do { if (randomNo < 30) { // eslint-disable-next-line no-unused-expressions ("Do not give up. Try again."); } else if (randomNo < 60) { // eslint-disable-next-line no-unused-expressions ("You are a lucky guy"); } else { // eslint-disable-next-line no-unused-expressions ("You are soooo lucky!"); } }; return (

Your Lucky number is: "{randomNo}"

{message}

); } } ================================================ FILE: examples/with-custom-target-babel-config/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; import App from './App'; hydrate( , document.getElementById('root') ); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-custom-target-babel-config/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-custom-target-babel-config/src/server.js ================================================ import { StaticRouter } from 'react-router-dom'; import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const context = {}; const markup = renderToString( ); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-custom-webpack-config/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-custom-webpack-config/README.md ================================================ # Razzle Custom Webpack Configuration Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-custom-webpack-config with-custom-webpack-config cd with-custom-webpack-config yarn start ``` ## Idea behind the example This example demonstrates how to use a `razzle.config.js` file to modify Razzle's underlying webpack configuration. It modifies the name of the server's output file in production (`razzle build`). Note that this file is not transpiled, and so you must write it with vanilla Node.js-compatible JavaScript. ```js // razzle.config.js 'use strict'; module.exports = { modifyWebpackConfig(opts) { const config = opts.webpackConfig; // Change the name of the server output file in production if (opts.env.target === 'node' && !opts.env.dev) { config.output.filename = 'custom.js'; } return config; }, }; ``` ================================================ FILE: examples/with-custom-webpack-config/package.json ================================================ { "name": "razzle-examples-with-custom-webpack-config", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/custom.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-custom-webpack-config/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-custom-webpack-config/razzle.config.js ================================================ 'use strict'; module.exports = { modifyWebpackConfig(opts) { const config = opts.webpackConfig; // Change the name of the server output file in production if (opts.env.target === 'node' && !opts.env.dev) { config.output.filename = 'custom.js'; } return config; }, }; ================================================ FILE: examples/with-custom-webpack-config/src/App.js ================================================ import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-custom-webpack-config/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-custom-webpack-config/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-custom-webpack-config/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-devcert-https/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-devcert-https/README.md ================================================ # Razzle Devcert Https Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-devcert-https with-devcert-https cd with-devcert-https yarn start ``` ## Idea behind the example This example demonstrates how to use a `razzle.config.js` file to modify Razzle's underlying configuration using a promise. It modifies the name of the server's output file in production (`razzle build`). Note that this file is not transpiled, and so you must write it with vanilla Node.js-compatible JavaScript. ```js // razzle.config.js 'use strict'; module.exports = { modifyWebpackOptions(opts) { const options = opts.webpackOptions; return new Promise(async (resolve) => { const httpsCredentials = await devcert.certificateFor('localhost'); const stringHttpsCredentials = { key: httpsCredentials.key.toString(), cert: httpsCredentials.cert.toString() }; if (opts.env.target === 'node' && opts.env.dev) { options.definePluginOptions.HTTPS_CREDENTIALS = JSON.stringify(stringHttpsCredentials); } if (opts.env.target === 'web' && opts.env.dev) { options.HTTPS_CREDENTIALS = httpsCredentials; } resolve(options); }); }, modifyWebpackConfig(opts) { const config = opts.webpackConfig; const options = opts.webpackOptions; if (opts.env.target === 'web' && opts.env.dev) { config.devServer.https = options.HTTPS_CREDENTIALS; } return config; }, }; ``` ================================================ FILE: examples/with-devcert-https/package.json ================================================ { "name": "razzle-examples-with-devcert-https", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/custom.js" }, "dependencies": { "cors": "^2.8.5", "express": "^4.17.1", "https": "^1.0.0", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "babel-preset-razzle": "4.2.15", "devcert": "^1.1.3", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-devcert-https/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-devcert-https/razzle.config.js ================================================ 'use strict'; const devcert = require('devcert'); const cors = require('cors'); const whitelist = ['https://localhost:3000', 'https://localhost:3001']; //white list consumers const corsOptions = { origin: '*', // function (origin, callback) { // console.log(origin); // if (whitelist.indexOf(origin) !== -1) { // callback(null, true); // } else { // callback(null, false); // } // }, methods: ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS'], optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204 credentials: true, //Credentials are cookies, authorization headers or TLS client certificates. allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'device-remember-token', 'Access-Control-Allow-Origin', 'Origin', 'Accept'] }; module.exports = { modifyOptions(opts) { // use modifyOptions so certificateFor is called once const options = opts.options.razzleOptions; return new Promise(async (resolve) => { const httpsCredentials = await devcert.certificateFor('localhost'); const stringHttpsCredentials = { key: httpsCredentials.key.toString(), cert: httpsCredentials.cert.toString() }; options.HTTPS_CREDENTIALS = stringHttpsCredentials; resolve(options); }); }, modifyWebpackOptions(opts) { const razzleOptions = opts.options.razzleOptions; const webpackOptions = opts.options.webpackOptions; if (opts.env.target === 'node' && opts.env.dev) { webpackOptions.definePluginOptions.HTTPS_CREDENTIALS = JSON.stringify(razzleOptions.HTTPS_CREDENTIALS); } return webpackOptions; }, modifyWebpackConfig(opts) { const config = opts.webpackConfig; const options = opts.options.razzleOptions; if (opts.env.target === 'web' && opts.env.dev) { config.devServer.https = options.HTTPS_CREDENTIALS; // config.devServer.before = function (app, server, compiler) { // app.use(cors('*')); console.log('web'); // // } config.devServer.headers = { "Access-Control-Allow-Origin": "*", https: true } } return config; }, }; ================================================ FILE: examples/with-devcert-https/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-devcert-https/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-devcert-https/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-devcert-https/src/index.js ================================================ import express from 'express'; import https from 'https'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; const credentials = HTTPS_CREDENTIALS || {}; export default https.createServer(credentials,app) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-devcert-https/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import cors from 'cors'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const whitelist = ['https://localhost:3000', 'https://localhost:3001']; //white list consumers const corsOptions = { origin: function (origin, callback) { if (whitelist.indexOf(origin) !== -1) { callback(null, true); } else { callback(null, false); } }, methods: ['GET', 'PUT', 'POST', 'DELETE', 'OPTIONS'], optionsSuccessStatus: 200, // some legacy browsers (IE11, various SmartTVs) choke on 204 credentials: true, //Credentials are cookies, authorization headers or TLS client certificates. allowedHeaders: ['Content-Type', 'Authorization', 'X-Requested-With', 'device-remember-token', 'Access-Control-Allow-Origin', 'Origin', 'Accept'] }; const server = express(); server .disable('x-powered-by') .use(cors(corsOptions)) .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-development-build/README.md ================================================ # Razzle Basic Example ## How to use This is the canary release documentation for this example Create and start the example: ```bash npx create-razzle-app@canary --example basic basic cd basic yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle to produce a development build. It satisfies the entry points `src/index.js` for the server and and `src/client.js` for the browser. The only differences between this example and the `basic` example are that the `razzle build` command is replaced with `razzle build --node-env=development` and that there is a new `start:dev` command for running the development build. You can use this command separately in a new script inside the `scripts` section of the project's `package.json` file, if you find it useful. ================================================ FILE: examples/with-development-build/gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-development-build/package.json ================================================ { "name": "razzle-examples-with-development-build", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build --node-env=development", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js", "start:dev": "NODE_ENV=development node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-development-build/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-development-build/sandbox.config.json ================================================ { "container": { "port": 3000 } } ================================================ FILE: examples/with-development-build/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-development-build/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-development-build/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-development-build/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-development-build/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-development-build/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-elm/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store # Compiled binary addons (http://nodejs.org/api/addons.html) build/Release coverage node_modules build .env.local .env.development.local .env.test.local .env.production.local .elm-static-html build # Optional npm cache directory .npm yarn.lock # Optional REPL history .node_repl_history # elm-package generated files elm-stuff/ # elm-repl generated files repl-temp-* ignore dist ================================================ FILE: examples/with-elm/README.md ================================================ # Razzle Elm Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-elm with-elm cd with-elm yarn start ``` ## Idea behind the example This is a basic example of how to use Razzle and Elm, it uses: * [elm-static-html](https://github.com/eeue56/elm-static-html-lib) to convert Elm views into raw html * [elm-webpack-loader](https://github.com/elm-community/elm-webpack-loader) load elm files and import them into javascript * [elm-hot-loader](https://github.com/fluxxu/elm-hot-loader) hot reload all Elm files while dev `src/client.js` contains all the js code required to load Elm, you can configure Elm ports here `src/server.js` the server side, here call `elm-static-html-lib` with the respective module to render the view --- If you want to activate the Elm debug mode or other tooling and debug utilites of Elm edit `razzle.config.js`: ```js { loader: 'elm-webpack-loader', options: { //Edit here verbose: true, warn: true, pathToMake: require('elm/platform').executablePaths['elm-make'], forceWatch: true } } ``` As of Razzle 2.0, you can now use [razzle-plugin-elm](../../packages/razzle-plugin-elm/README.md) instead of adding the webpack loaders on your own. ================================================ FILE: examples/with-elm/elm-package.json ================================================ { "version": "1.0.0", "summary": "helpful summary of your project, less than 80 characters", "repository": "https://github.com/user/project.git", "license": "BSD3", "source-directories": [ "src" ], "exposed-modules": [], "dependencies": { "elm-lang/core": "5.1.1 <= v < 6.0.0", "elm-lang/html": "2.0.0 <= v < 3.0.0", "eeue56/elm-html-in-elm":"2.0.0 <= v < 3.0.0" }, "elm-version": "0.18.0 <= v < 0.19.0" } ================================================ FILE: examples/with-elm/package.json ================================================ { "name": "razzle-examples-with-elm", "version": "4.2.15", "license": "MIT", "scripts": { "postinstall": "elm-package install -y", "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "set NODE_ENV=production&&node build/server.js" }, "dependencies": { "elm-static-html-lib": "^0.1.0", "express": "^4.17.1" }, "devDependencies": { "elm-hot-loader": "^0.5.4", "elm-webpack-loader": "4.5.0", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-elm/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-elm/razzle.config.js ================================================ 'use strict'; module.exports = { modifyWebpackOptions({ env: { target, // the target 'node' or 'web' dev, // is this a development build? true or false }, webpackObject, // the imported webpack node module options: { razzleOptions, // the modified options passed to Razzle in the `options` key in `razzle.config.js` (options: { key: 'value'}) webpackOptions, // the modified options that was used to configure webpack/ webpack loaders and plugins }, paths, // the modified paths that will be used by Razzle. }) { webpackOptions.fileLoaderExclude.push(/\.(elm)$/); return webpackOptions; }, modifyWebpackConfig(opts) { const config = opts.webpackConfig; config.module.noParse = [/.elm$/]; config.resolve.extensions.push('.elm'); if (opts.env.dev) { config.module.rules.push({ test: /\.elm$/, exclude: [/elm-stuff/, /node_modules/], use: [ { loader: 'elm-webpack-loader', options: { verbose: true, warn: true, pathToMake: require('elm/platform').executablePaths['elm-make'], forceWatch: true, }, }, ], }); } else { // Production config.module.rules.push({ test: /\.elm$/, exclude: [/elm-stuff/, /node_modules/], use: [ { loader: 'elm-webpack-loader', options: { pathToMake: require('elm/platform').executablePaths['elm-make'], }, }, ], }); } return config; }, }; ================================================ FILE: examples/with-elm/src/App.elm ================================================ module App exposing (..) import Html exposing (..) import Html.Attributes exposing (..) import Html.Events exposing (..) import Json.Decode type alias Model = {counter: Int} init : ( Model, Cmd Msg ) init = ( Model 0, Cmd.none ) decodeModel : Json.Decode.Decoder Model decodeModel = Json.Decode.map Model (Json.Decode.field "counter" Json.Decode.int) -- UPDATE type Msg = Inc update : Msg -> Model -> ( Model, Cmd Msg ) update message model = case message of Inc -> {model | counter = model.counter + 1} ! [] -- VIEW view : Model -> Html Msg view model = div [ class "container" ] [ h1 [] [ text "Elm SSR example" ] , p [] [ text "Click on the button below to increment the state." ] , div [] [ button [ class "btn btn-primary" , onClick Inc ] [ text "+ 1" ] , text <| toString model ] , p [] [ text "A simple example of how to make Razzle and Elm work together!" ] ] ================================================ FILE: examples/with-elm/src/Main.elm ================================================ module Main exposing (main) import Html import App exposing (init, update, view) main : Program Never App.Model App.Msg main = Html.program { init = init , update = update , view = view , subscriptions = always Sub.none } ================================================ FILE: examples/with-elm/src/client.js ================================================ import Elm from './Main'; // We need embed the Elm app to the div, if we call fullscreen we will have duplicated html Elm.Main.embed(document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-elm/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-elm/src/server.js ================================================ import elmStaticHtml from "elm-static-html-lib"; import express from 'express'; require('./Main'); const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const model = { counter: 5 }; const options = { model : model, decoder: "App.decodeModel" }; const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { return new Promise((resolve, reject) { elmStaticHtml(process.cwd(), "App.view", options) .then((markup) => { const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; resolve({ html, status: 200 }); }).catch((error) => { resolve({ html: `

An error ocurred on server, please try later, or contact support

`, status: 500 }); }); }) }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', async (req, res) => { const { html, status } = await renderApp(req, res); res.status(status).send(html); }); export default server; ================================================ FILE: examples/with-esbuild-loader/.eslintrc.js ================================================ module.exports = { "env": { "node": true, "browser": true, "es6": true }, "globals": { "Atomics": "readonly", "SharedArrayBuffer": "readonly" }, "parser": "@typescript-eslint/parser", "parserOptions": { "ecmaFeatures": { "jsx": true }, "ecmaVersion": 2018, "sourceType": "module" }, "plugins": ["react", "@typescript-eslint", "prettier"], "extends": [ "plugin:react/recommended", "airbnb", "plugin:prettier/recommended", "no-use-before-define": "off", "@typescript-eslint/no-use-before-define": ["error"], "plugin:@typescript-eslint/eslint-recommended", "plugin:@typescript-eslint/recommended" ], "rules": { "import/extensions": [ "error", "ignorePackages", { "js": "never", "jsx": "never", "ts": "never", "tsx": "never" } ], "prettier/prettier": "error", "@typescript-eslint/explicit-function-return-type": "off", "@typescript-eslint/no-unused-vars": "off", "react/jsx-filename-extension": [ 1, { "extensions": [".js", ".jsx", ".ts", ".tsx"] } ] }, "settings": { "import/resolver": { "node": { "extensions": [".js", ".jsx", ".ts", ".tsx"] } } } }; ================================================ FILE: examples/with-esbuild-loader/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-esbuild-loader/README.md ================================================ # Razzle Esbuild Loader Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-esbuild-loader with-esbuild-loader cd with-esbuild-loader yarn start ``` ## Idea behind the example This is an of how to use Razzle with [TypeScript](https://github.com/Microsoft/TypeScript). In `razzle.config.js`, we locate the part of the webpack configuration that is running `babel-loader` and swap it out for `ts-loader`. Additionally, we make sure Razzle knows how to resolve `.ts` and `.tsx` files. Lastly, we also need to modify our Jest configuration to handle typescript files. Thus we add `ts-jest` and `@types/jest` to our dev dependencies. Then we augment Razzle's default jest setup by adding a field in our `package.json`. ```json // package.json { ... "jest": { "transform": { "\\.(ts|tsx)$": "/node_modules/ts-jest/preprocessor.js", "\\.css$": "/node_modules/razzle/config/jest/cssTransform.js", "^(?!.*\\.(js|jsx|css|json)$)": "/node_modules/razzle/config/jest/fileTransform.js" }, "testMatch": [ "/src/**/__tests__/**/*.(ts|js)?(x)", "/src/**/?(*.)(spec|test).(ts|js)?(x)" ], "moduleFileExtensions": [ "ts", "tsx", "js", "json" ], "collectCoverageFrom": [ "src/**/*.{js,jsx,ts,tsx}" ] } } ``` The `tslint.json` and `tsconfig.json` are taken from Microsoft's official [TypeScript-React-Starter](https://github.com/Microsoft/TypeScript-React-Starter). Note: You do not techincally _need_ to fully replace `babel-loader` with `ts-loader` to use TypeScript. Both TS and Babel transpile ES6 code, so when you run both webpack loaders you are making Razzle do twice the work. From our testing, this can make HMR extremely slow on larger apps. Thus, this example overwrites `babel-loader` with `ts-loader`. However, if you are incrementally moving to typescript you may want to run both loaders side by side. If you are running both, add this to your `jest.transform` setup in `package.json`: ``` "^.+\\.(js|jsx)$": "/node_modules/razzle/config/jest/babelTransform.js", ``` This will continue to transform .js files through babel. ================================================ FILE: examples/with-esbuild-loader/package.json ================================================ { "name": "razzle-examples-with-typescript", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1", "react-router-dom": "^5.0.1" }, "devDependencies": { "@types/express": "^4.17.0", "@types/jest": "^26.0.20", "@types/node": "^14.14.22", "@types/react": "^17.0.0", "@types/react-dom": "^17.0.0", "@types/react-router-dom": "^5.1.7", "@types/webpack-env": "^1.14.0", "@typescript-eslint/eslint-plugin": "^4.14.1", "@typescript-eslint/parser": "^4.14.1", "esbuild-loader": "^2.11.1", "eslint": "^7.18.0", "eslint-config-airbnb": "^18.2.1", "eslint-config-prettier": "^7.2.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-node": "^11.1.0", "eslint-plugin-prettier": "^3.3.1", "eslint-plugin-react": "^7.22.0", "html-webpack-plugin": "^4.5.2", "mini-css-extract-plugin": "^0.9.0", "prettier": "^2.2.1", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "razzle-plugin-typescript": "4.2.15", "ts-jest": "^26.5.0", "typescript": "^4.1.3", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" }, "jest": { "transform": { "\\.(ts|tsx)$": "ts-jest", "\\.css$": "/node_modules/razzle/config/jest/cssTransform.js", "^(?!.*\\.(js|jsx|css|json)$)": "/node_modules/razzle/config/jest/fileTransform.js" }, "testMatch": [ "/src/**/__tests__/**/*.(ts|js)?(x)", "/src/**/?(*.)(spec|test).(ts|js)?(x)" ], "moduleFileExtensions": [ "ts", "tsx", "js", "json" ], "collectCoverageFrom": [ "src/**/*.{js,jsx,ts,tsx}" ] } } ================================================ FILE: examples/with-esbuild-loader/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-esbuild-loader/razzle.config.js ================================================ 'use strict'; const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin'); const makeLoaderFinder = require('razzle-dev-utils/makeLoaderFinder'); module.exports = { modifyWebpackConfig(opts) { const config = Object.assign({}, opts.webpackConfig); config.resolve.extensions = [...config.resolve.extensions, '.ts', '.tsx']; // Safely locate Babel-Loader in Razzle's webpack internals const babelLoaderFinder = makeLoaderFinder('babel-loader'); const babelLoader = config.module.rules.find(babelLoaderFinder); // Get the correct `include` option, since that hasn't changed. // This tells Razzle which directories to transform. const { include } = babelLoader; // Configure esbuild-loader const esbuildLoader = { include, test: /\.tsx?$/, use: [ { loader: require.resolve('esbuild-loader'), options: { loader: 'tsx', target: opts.env.target === 'web' ? 'es6' : 'node12', tsconfigRaw: require('./tsconfig.json'), }, }, ], }; // Remove babel config.module.rules = config.module.rules.filter( (rule) => !babelLoaderFinder(rule) ); config.module.rules.push(esbuildLoader); // Do typechecking in a separate process, // We can run it only in client builds. if (opts.env.target === 'web') { config.plugins.push( new ForkTsCheckerWebpackPlugin({ typescript: { build: true, configFile: './tsconfig.json', }, }) ); if (opts.env.dev) { // As suggested by Microsoft's Outlook team, these optimizations // crank up Webpack x TypeScript perf. // @see https://medium.com/@kenneth_chau/speeding-up-webpack-typescript-incremental-builds-by-7x-3912ba4c1d15 config.output.pathinfo = false; config.optimization = { removeAvailableModules: false, removeEmptyChunks: false, splitChunks: false, }; } } return config; }, }; ================================================ FILE: examples/with-esbuild-loader/src/App.css ================================================ body { margin: 0; padding: 0; font-family: sans-serif; } ================================================ FILE: examples/with-esbuild-loader/src/App.test.tsx ================================================ import React from 'react'; import { render } from 'react-dom'; import App from './App'; import { MemoryRouter } from 'react-router-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); render( , div ); }); }); ================================================ FILE: examples/with-esbuild-loader/src/App.tsx ================================================ import React from 'react'; import { Route, Switch } from 'react-router-dom'; import Home from './Home'; import './App.css'; const App = () => ( ); export default App; ================================================ FILE: examples/with-esbuild-loader/src/Home.css ================================================ .Home { text-align: center; } .Home-logo { animation: Home-logo-spin infinite 20s linear; height: 80px; } .Home-header { background-color: #222; height: 150px; padding: 20px; color: white; } .Home-intro { font-size: large; } .Home-resources { list-style: none; } .Home-resources > li { display: inline-block; padding: 1rem; } @keyframes Home-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ================================================ FILE: examples/with-esbuild-loader/src/Home.tsx ================================================ import React from 'react'; import logo from './react.svg'; import './Home.css'; class Home extends React.Component<{}, {}> { public render() { return (
logo

Welcome to Razzle

To get started, edit src/App.tsx or{' '} src/Home.tsx and save to reload.

); } } export default Home; ================================================ FILE: examples/with-esbuild-loader/src/client.tsx ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; import App from './App'; hydrate( , document.getElementById('root') ); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-esbuild-loader/src/index.ts ================================================ import express from 'express'; // this require is necessary for server HMR to recover from error // tslint:disable-next-line:no-var-requires let app = require('./server').default; if (module.hot) { module.hot.accept('./server', () => { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT ? parseInt(process.env.PORT, 10) : 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, (err: Error) => { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-esbuild-loader/src/server.tsx ================================================ import express from 'express'; import React from 'react'; import { renderToString } from 'react-dom/server'; import { StaticRouter } from 'react-router-dom'; import App from './App'; let assets: any; const syncLoadAssets = () => { assets = require(process.env.RAZZLE_ASSETS_MANIFEST!); }; syncLoadAssets(); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req: express.Request, res: express.Response) => { const context: any = {}; const markup = renderToString( ); if (context.url) { return { redirect: context.url }; } else { const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; } }; const server = express() .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR!)) .get('/*', (req: express.Request, res: express.Response) => { const { html = '', redirect = false } = renderApp(req, res); if (redirect) { res.redirect(redirect); } else { res.send(html); } }); export default server; ================================================ FILE: examples/with-esbuild-loader/tsconfig.json ================================================ { "compilerOptions": { "allowJs": true, "allowUnreachableCode": false, "noFallthroughCasesInSwitch": true, "allowSyntheticDefaultImports": true, "downlevelIteration": true, "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "jsx": "react", "lib": ["es6", "es2015", "es2017", "dom"], "module": "commonjs", "moduleResolution": "Node", "noImplicitAny": true, "noImplicitReturns": true, "noImplicitThis": true, "noUnusedLocals": false, "sourceMap": true, "strictNullChecks": true, "strict": false, "pretty": true, "suppressImplicitAnyIndexErrors": true, "target": "esnext" }, "exclude": [ "node_modules", "build", "scripts", "acceptance-tests", "webpack", "jest", "razzle.config.js" ], "types": ["typePatches", "node", "webpack-env"] } ================================================ FILE: examples/with-esbuild-loader/typings/index.d.ts ================================================ declare module '*.svg' { const content: any; export default content; } ================================================ FILE: examples/with-eslint/.eslintrc.json ================================================ { "extends": "eslint:recommended", "env": { "browser": true, "commonjs": true, "node": true, "es6": false }, "parserOptions": { "ecmaVersion": 6 }, "rules": { "no-console": "off", "strict": ["error", "global"], "curly": "warn" } } ================================================ FILE: examples/with-eslint/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-eslint/README.md ================================================ # Razzle Basic Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-eslint with-eslint cd with-eslint yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle. It satisfies the entry points `src/index.js` for the server and and `src/client.js` for the browser. ================================================ FILE: examples/with-eslint/package.json ================================================ { "name": "razzle-examples-with-eslint", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "@typescript-eslint/eslint-plugin": "^4.0.0", "@typescript-eslint/parser": "^4.14.1", "babel-eslint": "^10.1.0", "babel-preset-razzle": "4.2.15", "eslint": "^7.18.0", "eslint-config-react-app": "^6.0.0", "eslint-plugin-flowtype": "^5.2.0", "eslint-plugin-import": "^2.22.1", "eslint-plugin-jsx-a11y": "^6.4.1", "eslint-plugin-react": "^7.22.0", "eslint-plugin-react-hooks": "^4.2.0", "eslint-webpack-plugin": "^2.1.0", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "razzle-plugin-eslint": "4.2.15", "react-dev-utils": "^11.0.1", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-eslint/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-eslint/razzle.config.js ================================================ 'use strict'; module.exports = { options: { verbose: true }, plugins: ['eslint'], }; ================================================ FILE: examples/with-eslint/sandbox.config.json ================================================ { "container": { "port": 3000 } } ================================================ FILE: examples/with-eslint/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-eslint/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-eslint/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-eslint/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-eslint/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-eslint/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-experimental-refresh/README.md ================================================ # Razzle Experimental React Refresh Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-experimental-refresh with-experimental-refresh cd with-experimental-refresh yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle. It satisfies the entry points `src/index.js` for the server and and `src/client.js` for the browser. This is an **experimental** demo of React Fast Refresh. Please do not use these features in your application or project (yet). ================================================ FILE: examples/with-experimental-refresh/package.json ================================================ { "name": "razzle-examples-with-experimental-refresh", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start --verbose", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-experimental-refresh/razzle.config.js ================================================ module.exports = { options: { enableReactRefresh: true, }, } ================================================ FILE: examples/with-experimental-refresh/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-experimental-refresh/src/App.js ================================================ import * as React from 'react' import { useCallback, useEffect, useState } from 'react' import ClickCount from './components/ClickCount' import './global.css' import styles from './components/ClickCount.module.css' function a() { console.log( // hello document.body() ) } function foo() { a() } function App() { const [count, setCount] = useState(0) const increment = useCallback(() => { setCount(v => v + 1) }, [setCount]) useEffect(() => { const r = setInterval(() => { increment() }, 250) return () => { clearInterval(r) } }, [increment]) return (

Home

Auto Incrementing Value

Current value: {count}


Component with State


) } export default App; ================================================ FILE: examples/with-experimental-refresh/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-experimental-refresh/src/client.js ================================================ import * as React from 'react' import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-experimental-refresh/src/components/ClickCount.js ================================================ import * as React from 'react' import { useCallback, useState } from 'react' import styles from './ClickCount.module.css' export default function ClickCount() { const [count, setCount] = useState(0) const increment = useCallback(() => { setCount(v => v + 1) }, [setCount]) return ( ) } ================================================ FILE: examples/with-experimental-refresh/src/components/ClickCount.module.css ================================================ button.btn { margin: 0; border: 1px solid #d1d1d1; border-radius: 5px; padding: 0.5em; vertical-align: middle; white-space: normal; background: none; line-height: 1; font-size: 1rem; font-family: inherit; transition: all 0.2s ease; } button.btn { padding: 0.65em 1em; background: #0076ff; color: #fff; border: none; cursor: pointer; transition: all 0.2s ease; } button.btn:focus { outline: 0; border-color: #0076ff; } button.btn:hover { background: rgba(0, 118, 255, 0.8); } button.btn:focus { box-shadow: 0 0 0 2px rgba(0, 118, 255, 0.5); } ================================================ FILE: examples/with-experimental-refresh/src/global.css ================================================ body { font-family: 'SF Pro Text', 'SF Pro Icons', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif; padding: 20px 20px 60px; max-width: 680px; margin: 0 auto; font-size: 16px; line-height: 1.65; word-break: break-word; font-kerning: auto; font-variant: normal; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; text-rendering: optimizeLegibility; hyphens: auto; } h2, h3, h4 { margin-top: 1.5em; } code, pre { font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono, Bitstream Vera Sans Mono, Courier New, monospace, serif; font-size: 0.92em; color: #d400ff; } code:before, code:after { content: '`'; } hr { border: none; border-bottom: 1px solid #efefef; margin: 5em auto; } ================================================ FILE: examples/with-experimental-refresh/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-experimental-refresh/src/server.js ================================================ import App from './App'; import * as React from 'react' import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-fastify/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-fastify/README.md ================================================ # Razzle Fastify Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-fastify with-fastify cd with-fastify yarn start ``` ## Idea behind the example This is an example of how to use Razzle with [Fastify](https://www.fastify.io/) and includes [TypeScript](https://github.com/Microsoft/TypeScript). It is a very similar implementation to `with-koa` but with help from that example itself (found [here](https://github.com/jaredpalmer/razzle/blob/master/examples/with-koa/src/index.js)) and from the Fastify docs for serverless application [Serverless](https://www.fastify.io/docs/latest/Serverless/#should-you-use-fastify-in-a-serverless-platform#Vercel). ### TypeScript Basic razzle will uses Babel to transform TypeScript to plain JavaScript ( with babel-loader ), and uses TypeScript for type-checking. Razzle knows how to resolve `.ts` and `.tsx` files out of the box. ================================================ FILE: examples/with-fastify/package.json ================================================ { "name": "razzle-examples-with-fastify", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "fastify": "^3.20.2", "fastify-static": "^4.2.3", "react": "^17.0.1", "react-dom": "^17.0.1", "react-router-dom": "^5.1.2" }, "devDependencies": { "@testing-library/dom": "^7.29.4", "@testing-library/jest-dom": "^5.5.0", "@testing-library/react": "^10.0.3", "@testing-library/user-event": "^10.1.0", "@types/express": "^4.17.6", "@types/jest": "^25.2.1", "@types/node": "^13.13.2", "@types/react": "^16.9.34", "@types/react-dom": "^16.9.6", "@types/react-router-dom": "^5.1.4", "@types/webpack-env": "^1.15.2", "babel-preset-razzle": "4.2.15", "cross-env": "^7.0.3", "express": "^4.17.1", "html-webpack-plugin": "^4.5.2", "mini-css-extract-plugin": "^0.9.0", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "typescript": "^4.0.3", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-fastify/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-fastify/src/App.css ================================================ body { margin: 0; padding: 0; font-family: sans-serif; } ================================================ FILE: examples/with-fastify/src/App.test.tsx ================================================ import { render } from '@testing-library/react'; import React from 'react'; import { MemoryRouter } from 'react-router-dom'; import App from './App'; test('renders learn react link', () => { const { getByText } = render( ); const linkElement = getByText(/welcome to razzles/i); expect(linkElement).toBeInTheDocument(); }); ================================================ FILE: examples/with-fastify/src/App.tsx ================================================ import React from 'react'; import { Route, Switch } from 'react-router-dom'; import './App.css'; import Home from './Home'; const App = () => ( ); export default App; ================================================ FILE: examples/with-fastify/src/Home.css ================================================ .Home { text-align: center; } .Home-logo { animation: Home-logo-spin infinite 20s linear; height: 80px; } .Home-header { background-color: #222; height: 150px; padding: 20px; color: white; } .Home-intro { font-size: large; } .Home-resources { list-style: none; } .Home-resources > li { display: inline-block; padding: 1rem; } @keyframes Home-logo-spin { from { transform: rotate(0deg); } to { transform: rotate(360deg); } } ================================================ FILE: examples/with-fastify/src/Home.tsx ================================================ import React from 'react'; import './Home.css'; import logo from './react.svg'; class Home extends React.Component<{}, {}> { public render() { return (
logo

Welcome to Razzle

To get started, edit src/App.tsx or{' '} src/Home.tsx and save to reload.

); } } export default Home; ================================================ FILE: examples/with-fastify/src/client.tsx ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; import App from './App'; hydrate( , document.getElementById('root') ); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-fastify/src/index.ts ================================================ import http from 'http'; /** * This implementation is similar to the `with-koa` example, * but Fastify does not have a `app#callback()` method. * Thus, this import implements a similar implementation. * See `./server.tsx` for more information. */ let currentHandler: http.RequestListener = require('./server').default; const server = http.createServer(currentHandler); const port = process.env.PORT || 3000; server.listen(port, () => { console.log(`🚀 Server Started on Port ${port}`); }); if (module.hot) { module.hot.accept('./server', async function() { console.log('🔁 HMR Reloading `./server`...'); try { const newHandler: http.RequestListener = require('./server').default; server.removeListener('request', currentHandler); server.on('request', newHandler); currentHandler = newHandler; } catch (error) { console.error('ERROR', error); } console.log('🚀 Server-side HMR Complete'); }); console.info('✅ Server-side HMR Enabled!'); } ================================================ FILE: examples/with-fastify/src/server.tsx ================================================ import fastify from "fastify"; import fastifyStatic from "fastify-static"; import type { IncomingMessage, ServerResponse } from "http"; import React from "react"; import { renderToString } from "react-dom/server"; import { StaticRouter } from "react-router-dom"; import App from "./App"; let assetsImport: Record; import(process.env.RAZZLE_ASSETS_MANIFEST!).then((res) => { assetsImport = res.default; }); const cssLinksFromAssets = (assets: Record, entryPoint: string) => (assets && assets[entryPoint]?.css?.map((asset: string) => ``).join("")) || ""; const jsScriptTagsFromAssets = (assets: Record, entryPoint: string, extra = "") => (assets && assets[entryPoint]?.js.map((asset: string) => ``).join("")) || ""; const app = fastify() .register(fastifyStatic, { root: process.env.RAZZLE_PUBLIC_DIR!, prefix: "/public" }) .get("/*", async (req, res) => { const context: { url?: string } = {}; const markup = renderToString( , ); if (context.url) { return res.redirect(context.url); } res .status(200) .type("text/html") .send( ` Welcome to Razzle ${cssLinksFromAssets(assetsImport, "client")}
${markup}
${jsScriptTagsFromAssets(assetsImport, "client", " defer crossorigin")} `, ); }); /** * This is a similar implementation to the one found in the Fastify docs, * which can be found [here]{@link https://www.fastify.io/docs/latest/Serverless/#should-you-use-fastify-in-a-serverless-platform#Vercel}. * The `app#ready()` is to indicate that all plugins have been loaded and the server is ready, * then the `app#server#emit()` method is called to handle the incoming request and Fastify handles it from there. */ export default async (req: IncomingMessage, res: ServerResponse): Promise => { await app.ready(); app.server.emit("request", req, res); }; ================================================ FILE: examples/with-fastify/src/setupTests.ts ================================================ // jest-dom adds custom jest matchers for asserting on DOM nodes. // allows you to do things like: // expect(element).toHaveTextContent(/react/i) // learn more: https://github.com/testing-library/jest-dom import '@testing-library/jest-dom/extend-expect'; ================================================ FILE: examples/with-fastify/tsconfig.json ================================================ { "compilerOptions": { "target": "esnext", "module": "commonjs", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": false, "forceConsistentCasingInFileNames": true, "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react", "typeRoots": ["node_modules/@types", "typings"] }, "include": ["src", "typings/*"] } ================================================ FILE: examples/with-fastify/typings/svg.d.ts ================================================ // https://www.typescriptlang.org/docs/handbook/modules.html#ambient-modules declare module '*.svg' { const src: string; export default src; } ================================================ FILE: examples/with-firebase-functions/.firebaserc ================================================ { "projects": { "default": "" } } ================================================ FILE: examples/with-firebase-functions/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-firebase-functions/README.md ================================================ # Razzle with Cloud Functions for Firebase example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-firebase-functions with-firebase-functions cd with-firebase-functions yarn start ``` Build client and server ```bash yarn build ``` Deploy to firebase ```bash yarn deploy ``` Access your app at `.firebaseapp.com` ## Idea behind the example This is a basic example of how to use razzle with firebase functions and firebase hosting. ================================================ FILE: examples/with-firebase-functions/firebase.json ================================================ { "hosting": { "public": "build/public", "ignore": [ "firebase.json", "**/.*", "**/node_modules/**" ], "rewrites": [ { "source": "**/**", "function": "app" } ] }, "functions": { "source": "." } } ================================================ FILE: examples/with-firebase-functions/index.js ================================================ 'use strict' const functions = require('firebase-functions'); const app = require('./server/build/server.bundle.js').default; exports.app = functions.https.onRequest(app) ================================================ FILE: examples/with-firebase-functions/package.json ================================================ { "name": "razzle-examples-with-firebase-functions", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "predeploy": "npm run build", "deploy": "firebase deploy" }, "dependencies": { "express": "^4.17.1", "firebase-admin": "^8.11.0", "firebase-functions": "^3.6.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-firebase-functions/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-firebase-functions/razzle.config.js ================================================ 'use strict'; const path = require('path'); module.exports = { modifyWebpackConfig(opts) { const config = opts.webpackConfig; if (opts.env.target === 'node' && !opts.env.dev) { config.entry = path.resolve(__dirname, './src/server.js'); config.output.filename = 'server.bundle.js'; config.output.path = path.resolve(__dirname, './server/build'); config.output.libraryTarget = 'commonjs2'; } return config; }, } ================================================ FILE: examples/with-firebase-functions/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-firebase-functions/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-firebase-functions/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-firebase-functions/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-firebase-functions/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-firebase-functions/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-heroku/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-heroku/Procfile ================================================ web: yarn start:prod ================================================ FILE: examples/with-heroku/README.md ================================================ # Razzle Heroku Deployment example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-heroku with-heroku cd with-heroku yarn start ``` ### Deploy to Heroku: [Heroku](https://www.heroku.com/) manages app deployments with [Git](https://devcenter.heroku.com/articles/git) so: #### Setup Git: ```bash git init git add git commit -m "Heroku deployment, first commit" ``` #### Setup Heroku: * Create a Heroku [account](https://signup.heroku.com/) * Install Heroku [CLI](https://devcenter.heroku.com/articles/heroku-cli) and [authenticate](https://devcenter.heroku.com/articles/authentication) * Create Heroku app: `heroku create` * or `heroku create ` if you want to specify an app name (checks for unique app name) * or `heroku git:remote -a ` if you already created an App in the [dashboard](https://dashboard.heroku.com/apps) * Verify with `git remote -v`: ``` heroku https://git.heroku.com/.git (fetch) heroku https://git.heroku.com/.git (push) ``` #### Deployment * `yarn deploy` or `git push heroku master` * or from another branch, other than **master**: `git push heroku :master` * Console should complete with: **_https://appname.herokuapp.com/ deployed to Heroku_** * Verify app by opening **_https://appname.herokuapp.com/_** #### 👉 Please note * Heroku expects a `yarn.lock` file to be able to recognise _yarn_ as your package manager and process the `yarn` commands - so make sure to run `yarn install` before deployment, and to commit the `yarn.lock` file. ## Idea behind the example This is a basic example of how to use razzle and deploy to [Heroku](https://www.heroku.com/) with [Git](https://devcenter.heroku.com/articles/git). ================================================ FILE: examples/with-heroku/package.json ================================================ { "name": "razzle-examples-with-heroku", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build --noninteractive", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js", "deploy": "git push heroku master" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-heroku/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-heroku/razzle.config.js ================================================ 'use strict'; module.exports = { options: { forceRuntimeEnvVars: ['HOST', 'PORT'] } }; ================================================ FILE: examples/with-heroku/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-heroku/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-heroku/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-heroku/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-heroku/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-heroku/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-hyperapp/.babelrc ================================================ { "presets": [ "razzle/babel" ], "plugins": [ [ "transform-react-jsx", { "pragma": "h" } ] ] } ================================================ FILE: examples/with-hyperapp/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-hyperapp/README.md ================================================ # Razzle Hyperapp Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-hyperapp with-hyperapp cd with-hyperapp yarn start ``` ## Idea behind the example This shows how to setup [Hyperapp](https://github.com/hyperapp/hyperapp/) with Razzle. Here is a list of changes from Razzle's base template: 1. Install `babel-plugin-transform-react-jsx` as a devDependency. 2. Extend Razzle's babel config with a custom `.babelrc` 3. Install `hyperapp` and `"@hyperapp/render` 4. Remove `react`, `react-dom`, `react-router-dom` entirely 5. Update `server.js` to use `@hyperapp/render`'s `withRender` function. Also remove the `
` element from our html template since Hyperapp can render to the body. 6. Add a `main.js` file which exports the essential pieces of Hyperapp, which are the `state`, `actions`, and `view`. These are to be shared between the `server.js` and `client.js` files. ================================================ FILE: examples/with-hyperapp/package.json ================================================ { "name": "razzle-examples-with-hyperapp", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "@hyperapp/render": "^2.1.0", "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1", "hyperapp": "^1.2.5" }, "devDependencies": { "babel-plugin-transform-react-jsx": "^6.24.1", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-hyperapp/public/robots.txt ================================================ User-agent: * Disallow: /api/ Disallow: /publicapi/ Disallow: /query/ ================================================ FILE: examples/with-hyperapp/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Helvetica, Arial, sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol'; } ================================================ FILE: examples/with-hyperapp/src/App.js ================================================ /** @jsx h */ import { h } from 'hyperapp'; import HyperappLogo from './hyperapp.svg'; import './App.css'; const App = ({ state, actions }) => (
Hyperapp Logo

Hello Hyperapp!

Count is {state.count}

); export default App; ================================================ FILE: examples/with-hyperapp/src/App.test.js ================================================ /** @jsx h */ import { h } from 'hyperapp'; import { renderToString } from '@hyperapp/render'; import App from './App'; describe('', () => { test('renders without exploding', () => { const body = document.createElement('body'); const markup = renderToString(); expect(markup).toContain('App'); }); }); ================================================ FILE: examples/with-hyperapp/src/client.js ================================================ /** @jsx h */ import { app } from 'hyperapp'; import { state, actions, view } from './main'; app(state, actions, view, document.body); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-hyperapp/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-hyperapp/src/main.js ================================================ /** @jsx h */ import { h } from 'hyperapp'; import App from './App'; /* MODEL */ const state = { count: 0 }; /* UPDATE */ const actions = { down: value => state => ({ count: state.count - value }), up: value => state => ({ count: state.count + value }), }; /* VIEW */ const view = (state, actions) => ; export { state, actions, view }; ================================================ FILE: examples/with-hyperapp/src/main.test.js ================================================ import { app } from 'hyperapp'; import { withRender } from '@hyperapp/render'; import { state, actions, view } from './main'; describe('main app', () => { test('renders without exploding', () => { const body = document.createElement('body'); const markup = withRender(app)(state, actions, view, body).toString(); expect(markup).toContain('Hello Hyperapp'); }); }); ================================================ FILE: examples/with-hyperapp/src/server.js ================================================ /** @jsx h */ import express from 'express'; import { app } from 'hyperapp'; import { withRender } from '@hyperapp/render'; import { state, actions, view } from './main'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = withRender(app)(state, actions, view).toString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-inferno/.babelrc ================================================ { "presets": [ "razzle/babel" ], "plugins": [ "inferno" ] } ================================================ FILE: examples/with-inferno/.eslintrc ================================================ { "extends": ["plugin:inferno/recommended"], "plugins": ["inferno"], "parserOptions": { "sourceType": "module" }, "rules": { "no-unused-vars": 0 } } ================================================ FILE: examples/with-inferno/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-inferno/README.md ================================================ # Razzle Inferno Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-inferno with-inferno cd with-inferno yarn start ``` ## Idea behind the example This shows how to use [Inferno](https://github.com/infernojs) instead of React in a Razzle project. Here is a list of changes from Razzle's base template: 1. Install `babel-plugin-inferno` as a devDependency. 2. Extend Razzle's babel config with a custom `.babelrc` 3. Install `inferno`, `inferno-server`, `inferno-devtools`, `inferno-component` as dependencies 4. Remove `react`, `react-dom`, `react-router-dom` entirely 5. Update `server/server.js` to use `inferno-server`'s `renderToString` function. 6. Update `client.js` to configure Inferno for HMR. ================================================ FILE: examples/with-inferno/package.json ================================================ { "name": "razzle-examples-with-inferno", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "inferno": "7.4.2", "inferno-component": "7.4.2", "inferno-hydrate": "^7.4.2", "inferno-server": "7.4.2" }, "devDependencies": { "@babel/core": "^7.12.10", "eslint": "^7.18.0", "eslint-plugin-inferno": "^7.20.1", "babel-plugin-inferno": "6.1.0", "inferno-devtools": "7.4.2", "html-webpack-plugin": "^4.5.2", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-inferno/public/robots.txt ================================================ User-agent: * Disallow: /api/ Disallow: /publicapi/ Disallow: /query/ ================================================ FILE: examples/with-inferno/src/App.js ================================================ import Inferno from "inferno"; import Component from "inferno-component"; import InfernoLogo from "./inferno.svg"; class App extends Component { render() { return (
Inferno Logo Hello Inferno!
); } } export default App; ================================================ FILE: examples/with-inferno/src/client.js ================================================ import { hydrate } from "inferno-hydrate"; import App from "./App"; if (module.hot) { require("inferno-devtools"); } hydrate(, document.getElementById("root")); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-inferno/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-inferno/src/server.js ================================================ import App from './App'; import Inferno from 'inferno'; import { renderToString } from 'inferno-server'; import express from 'express'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-jest-snapshots/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-jest-snapshots/README.md ================================================ # Using Razzle and Jest Snapshots ## How to use Create and start the example: ```bash npx create-razzle-app --example with-jest-snapshots with-jest-snapshots cd with-jest-snapshots yarn start ``` ## Idea behind the example This is an example of how to use [Jest Snapshots](http://facebook.github.io/jest/docs/en/snapshot-testing.html#snapshot-testing-with-jest) with a Razzle project. > Snapshot tests are a very useful tool whenever you want to make sure your UI does not change unexpectedly. > A typical snapshot test case for a mobile app renders a UI component, takes a screenshot, then compares it to a reference image stored alongside the test. The test will fail if the two images do not match: either the change is unexpected, or the screenshot needs to be updated to the new version of the UI component. ```js // src/__tests__/Home.test.js import React from 'react'; import renderer from 'react-test-renderer'; import Home from '../Home'; it('renders Home correctly', () => { const tree = renderer.create().toJSON(); expect(tree).toMatchSnapshot(); }); ``` When you run `yarn test`, a snapshot file is generated that looks like: ``` // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders Home correctly 1`] = `
Hello World!
`; ``` Refer to the [Jest documentation](http://facebook.github.io/jest/docs/en/snapshot-testing.html#snapshot-testing-with-jest) for more information. ================================================ FILE: examples/with-jest-snapshots/package.json ================================================ { "name": "razzle-examples-with-jest", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "test": "razzle test --env=jsdom", "build": "razzle build", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1", "react-router-dom": "^5.1.2" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "react-test-renderer": "^16.13.1", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-jest-snapshots/public/robots.txt ================================================ User-agent: * Disallow: /api/ Disallow: /publicapi/ Disallow: /query/ ================================================ FILE: examples/with-jest-snapshots/src/App.js ================================================ import React from "react"; import { Route, Switch } from "react-router-dom"; import Home from "./Home"; const App = () => ( ); export default App; ================================================ FILE: examples/with-jest-snapshots/src/Home.js ================================================ import React from 'react'; const Home = () => { return (
Hello World!
); }; export default Home; ================================================ FILE: examples/with-jest-snapshots/src/__tests__/App.test.js ================================================ import React from "react"; import renderer from "react-test-renderer"; import { MemoryRouter } from "react-router-dom"; import App from "../App"; it("renders App correctly", () => { const tree = renderer .create( ) .toJSON(); expect(tree).toMatchSnapshot(); }); test("hello", async () => { const yo = await Promise.resolve("hello"); expect(yo).toEqual("hello"); }); ================================================ FILE: examples/with-jest-snapshots/src/__tests__/Home.test.js ================================================ import React from 'react'; import renderer from 'react-test-renderer'; import Home from '../Home'; it('renders Home correctly', () => { const tree = renderer.create().toJSON(); expect(tree).toMatchSnapshot(); }); ================================================ FILE: examples/with-jest-snapshots/src/__tests__/__snapshots__/App.test.js.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders App correctly 1`] = `
Hello World!
`; ================================================ FILE: examples/with-jest-snapshots/src/__tests__/__snapshots__/Home.test.js.snap ================================================ // Jest Snapshot v1, https://goo.gl/fbAQLP exports[`renders Home correctly 1`] = `
Hello World!
`; ================================================ FILE: examples/with-jest-snapshots/src/client.js ================================================ import React from "react"; import { hydrate } from "react-dom"; import { BrowserRouter } from "react-router-dom"; import App from "./App"; hydrate( , document.getElementById("root") ); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-jest-snapshots/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-jest-snapshots/src/server.js ================================================ import { StaticRouter } from 'react-router-dom'; import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString( ); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-jsconfig-paths/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-jsconfig-paths/README.md ================================================ # Razzle With Jsconfig Paths Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-jsconfig-paths with-jsconfig-paths cd with-jsconfig-paths yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle with jsconfig paths, this also works with tsconfig. It satisfies the entry points `src/index.js` for the server and and `src/client.js` for the browser. ================================================ FILE: examples/with-jsconfig-paths/here-is-extra/extra.js ================================================ import React from 'react'; const Extra = () =>
Something Extra.
; export default Extra; ================================================ FILE: examples/with-jsconfig-paths/jsconfig.json ================================================ { "compilerOptions": { "baseUrl": "src", "paths": { "extra/*": ["../here-is-extra/*"] } } } ================================================ FILE: examples/with-jsconfig-paths/package.json ================================================ { "name": "razzle-with-jsconfig-paths", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-jsconfig-paths/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-jsconfig-paths/sandbox.config.json ================================================ { "container": { "port": 3000 } } ================================================ FILE: examples/with-jsconfig-paths/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-jsconfig-paths/src/App.js ================================================ import './App.css'; import React from 'react'; import Extra from 'extra/extra'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-jsconfig-paths/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-jsconfig-paths/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-jsconfig-paths/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-jsconfig-paths/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-jsxstyle/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-jsxstyle/README.md ================================================ # Razzle JSXStyle Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-jsxstyle with-jsxstyle cd with-jsxstyle yarn start ``` ## Idea behind the example This is demo shows how to use [JSXXtyle](https://github.com/smyte/jsxstyle) and the new server rendering API with Razzle. On each request, JSXStyle will extract out styles into a variable called `styles` will all the critical CSS in the render tree that we can then just drop into our `` ```js import { injectAddRule, resetCache } from 'jsxstyle/lib/styleCache'; // .. server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { resetCache(); let styles = ''; const context = {}; injectAddRule(rule => (styles += rule + '\n')); const markup = renderToString( ); if (context.url) { res.redirect(context.url); } else { res.send( ` Welcome to Razzle ${assets.client.css ? `` : ''}
${markup}
` ); } }); ``` ================================================ FILE: examples/with-jsxstyle/package.json ================================================ { "name": "razzle-examples-with-jsxstyle", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "jsxstyle": "^2.3.1", "react": "^17.0.1", "react-dom": "^17.0.1", "react-router-dom": "^5.1.2" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-jsxstyle/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-jsxstyle/src/About.js ================================================ import { Block, InlineBlock } from 'jsxstyle'; import React, { Component } from 'react'; class About extends Component { render() { return ( To get started, edit src/App.js or{' '} src/About.js and save to reload. Docs Issues Community Slack ); } } export default About; ================================================ FILE: examples/with-jsxstyle/src/App.css ================================================ * { box-sizing: border-box; } html, body, #root { height: 100%; } body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } div { display: flex; flex-direction: column; flex-shrink: 0; min-width: 0; align-items: stretch; } ================================================ FILE: examples/with-jsxstyle/src/App.js ================================================ import "./App.css"; import { Block, InlineBlock } from "jsxstyle"; import About from "./About"; import Home from "./Home"; import { Link, Route, Switch } from "react-router-dom"; import React from "react"; const App = () => ( About Home ); export default App; ================================================ FILE: examples/with-jsxstyle/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; import { MemoryRouter } from 'react-router-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render( , div ); }); }); ================================================ FILE: examples/with-jsxstyle/src/Home.js ================================================ import { Block, InlineBlock } from 'jsxstyle'; import React, { Component } from 'react'; class Home extends Component { render() { return ( Razzle x JSXStyle To get started, edit src/App.js or{' '} src/Home.js and save to reload. Docs Issues Community Slack ); } } export default Home; ================================================ FILE: examples/with-jsxstyle/src/client.js ================================================ import App from "./App"; import { BrowserRouter } from "react-router-dom"; import React from "react"; import { hydrate } from "react-dom"; hydrate( , document.getElementById("root") ); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-jsxstyle/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-jsxstyle/src/server.js ================================================ import { cache } from 'jsxstyle'; import App from './App'; import React from 'react'; import { StaticRouter } from 'react-router-dom'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { cache.reset(); let styles = ''; cache.injectOptions({ onInsertRule(css) { styles += css; }, }); const context = {}; const markup = renderToString( ); if (context.url) { return { redirect: context.url }; } else { const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')} ${styles ? `` : ''}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; } }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html = '', redirect = false } = renderApp(req, res); if (redirect) { res.redirect(redirect); } else { res.send(html); } }); export default server; ================================================ FILE: examples/with-koa/README.md ================================================ # Using Razzle and Koa ## How to use Create and start the example: ```bash npx create-razzle-app --example with-koa with-koa cd with-koa yarn start ``` ## Idea behind the example This is an example of how to use [Koa][koa], a popular web application framework, with a Razzle project, as an alternative to the default [Express][express] `server.js` setup. Being minimalistic in its philosophy, [Koa][koa] doesn't include most required dependencies to mimic its [Express][express] counterpart, so this example relies on some additional packages. - `koa-static` ([docs][koa-static]) Static file serving middleware. Used to serve resources under `process.env.RAZZLE_PUBLIC_DIR`. - `koa-router` ([docs][koa-router]) Express-styling router middleware for [Koa][koa]. Will direct `HTTP GET` requests to your React client. - `koa-helmet` ([docs][koa-helmet]) Provides important security headers to make your app more secure by default. Among other things, it prevents the `X-Powered-By` header from [being sent to requesting clients][hide-powered-by]. --- For additional information, refer to [Koa offical documentation][koa-docs]. [razzle-repo]: https://github.com/jaredpalmer/razzle.git [koa]: http://koajs.com [express]: https://expressjs.com/ [koa-static]: https://github.com/koajs/static [koa-router]: https://github.com/alexmingoia/koa-router [koa-helmet]: https://github.com/venables/koa-helmet [hide-powered-by]: https://helmetjs.github.io/docs/hide-powered-by/ [koa-docs]: https://github.com/koajs/koa/tree/master/docs ================================================ FILE: examples/with-koa/package.json ================================================ { "name": "razzle-examples-with-koa", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "test": "razzle test --env=jsdom", "build": "razzle build", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "koa": "^2.13.1", "koa-helmet": "^6.1.0", "koa-router": "^10.0.0", "koa-static": "^5.0.0", "react": "^17.0.1", "react-dom": "^17.0.1", "react-router-dom": "^5.2.0" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-koa/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-koa/src/App.css ================================================ body, html { margin: 0; padding: 0; height: 100%; } body { font: 17px/1.5 "Lucida Grande", "Lucida Sans Unicode", Helvetica, Arial, Verdana, sans-serif; background: white; color: #33333d; overflow-y: scroll; overflow-x: hidden; } a { color: #33a0c0; } ================================================ FILE: examples/with-koa/src/App.js ================================================ import React from "react"; import { Route, Switch } from "react-router-dom"; import Home from "./Home"; import "./App.css"; const App = () => ( ); export default App; ================================================ FILE: examples/with-koa/src/App.test.js ================================================ import App from "./App"; import React from "react"; import ReactDOM from "react-dom"; import { MemoryRouter } from "react-router-dom"; describe("", () => { test("renders without exploding", () => { const div = document.createElement("div"); ReactDOM.render( , div ); }); }); ================================================ FILE: examples/with-koa/src/Home.css ================================================ .Home { text-align: center; } .Home-logo { height: 80px; } .Home-header { height: 150px; padding: 20px; } .Home-header h2 { font-size: 1.2em; } .Home-intro { border-top: 1px solid #eee; border-bottom: 1px solid #eee; padding: 25px; overflow-x: auto; font-size: .9em; } .Home-resources { list-style: none; } .Home-resources > li { display: inline-block; padding: 1rem; } ================================================ FILE: examples/with-koa/src/Home.js ================================================ import React from 'react'; import logo from './koajs-logo.png'; import './Home.css'; class Home extends React.Component { render() { return (
logo

Welcome to Razzle + Koa

          To get started, edit src/App.js or{' '}
          src/Home.js and save to reload.
        
); } } export default Home; ================================================ FILE: examples/with-koa/src/client.js ================================================ import App from "./App"; import { BrowserRouter } from "react-router-dom"; import React from "react"; import { hydrate } from "react-dom"; hydrate( , document.getElementById("root") ); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-koa/src/index.js ================================================ import http from 'http'; let app = require('./server').default; // Use `app#callback()` method here instead of directly // passing `app` as an argument to `createServer` (or use `app#listen()` instead) // @see https://github.com/koajs/koa/blob/master/docs/api/index.md#appcallback let currentHandler = app.callback(); const server = http.createServer(currentHandler); server.listen(process.env.PORT || 3000, error => { if (error) { console.log(error); } console.log('🚀 started'); }); if (module.hot) { console.log('✅ Server-side HMR Enabled!'); module.hot.accept('./server', () => { console.log('🔁 HMR Reloading `./server`...'); try { const newHandler = require('./server').default.callback(); server.removeListener('request', currentHandler); server.on('request', newHandler); currentHandler = newHandler; } catch (error) { console.error(error); } }); } ================================================ FILE: examples/with-koa/src/server.js ================================================ import App from './App'; import React from 'react'; import { StaticRouter } from 'react-router-dom'; import Koa from 'koa'; import serve from 'koa-static'; import helmet from 'koa-helmet'; import Router from 'koa-router'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (ctx) => { const context = {}; const markup = renderToString( ); if (context.url) { return { redirect: context.url }; } else { const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; } }; // Initialize `koa-router` and setup a route listening on `GET /*` // Logic has been splitted into two chained middleware functions // @see https://github.com/alexmingoia/koa-router#multiple-middleware const router = new Router(); router.get( '(.*)', (ctx, next) => { const { html = '', redirect = false } = renderApp(ctx); ctx.state.markup = html; return redirect ? ctx.redirect(redirect) : next(); }, ctx => { ctx.status = 200; ctx.body = ctx.state.markup; } ); // Intialize and configure Koa application const server = new Koa(); server // `koa-helmet` provides security headers to help prevent common, well known attacks // @see https://helmetjs.github.io/ .use(helmet()) // Serve static files located under `process.env.RAZZLE_PUBLIC_DIR` .use(serve(process.env.RAZZLE_PUBLIC_DIR)) .use(router.routes()) .use(router.allowedMethods()); export default server; ================================================ FILE: examples/with-less/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-less/README.md ================================================ # Razzle With LESS Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-less with-less cd with-less yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle. It satisfies the entry points and use less as styling language You can import anything from node_modules or other less files, like Ant Design, etc. `src/index.js` for the server, `src/client.js` for the browser, and `src/App.less` for LESS style. ================================================ FILE: examples/with-less/package.json ================================================ { "name": "razzle-examples-with-less", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "resolutions": { "postcss": "8.2.4" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "babel-preset-razzle": "4.2.15", "less": "^4.1.0", "mini-css-extract-plugin": "^0.9.0", "postcss": "^8.2.4", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "razzle-plugin-less": "4.2.15", "style-loader": "^2.0.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-less/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-less/razzle.config.js ================================================ 'use strict'; module.exports = { plugins: ['less'], }; ================================================ FILE: examples/with-less/src/App.js ================================================ import './App.less'; import React from 'react'; const App = () => (
Welcome to Razzle.
Hot reload enabled!!
); export default App; ================================================ FILE: examples/with-less/src/App.less ================================================ @import (css) url('https://fonts.googleapis.com/css?family=Open+Sans'); @import './other'; body { margin: 0; padding: 0; font-family: 'Open Sans', sans-serif; } ================================================ FILE: examples/with-less/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-less/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-less/src/index.js ================================================ import express from 'express'; import app from './server'; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-less/src/other.less ================================================ @info-color: darkmagenta; .info { color: @info-color; font-size: 14pt; } ================================================ FILE: examples/with-less/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-loadable-components/.babelrc ================================================ { "presets": ["razzle/babel"], "plugins": ["@loadable/babel-plugin"] } ================================================ FILE: examples/with-loadable-components/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-loadable-components/README.md ================================================ # Razzle loadable-components Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-loadable-components with-loadable-components cd with-loadable-components yarn start ``` ## Idea behind the example This sample has the full SSR setup as described in the [loadable-components docs](https://github.com/smooth-code/loadable-components#server-side-rendering). It demonstrates simple dynamic imports using [loadable-components](https://github.com/smooth-code/loadable-components) on top of SSR with razzle. ================================================ FILE: examples/with-loadable-components/package.json ================================================ { "name": "razzle-examples-with-loadable-components", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "export": "razzle export", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "@loadable/component": "^5.15.0", "@loadable/server": "^5.15.0", "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "@babel/core": "^7.12.10", "@loadable/babel-plugin": "^5.13.2", "@loadable/webpack-plugin": "^5.15.0", "babel-preset-razzle": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-loadable-components/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-loadable-components/razzle.config.js ================================================ const LoadableWebpackPlugin = require("@loadable/webpack-plugin"); const path = require("path"); module.exports = { modifyWebpackConfig(opts) { const config = opts.webpackConfig; // add loadable webpack plugin only // when we are building the client bundle if (opts.env.target === "web") { const filename = path.resolve(__dirname, "build"); // saving stats file to build folder // without this, stats files will go into // build/public folder config.plugins.push( new LoadableWebpackPlugin({ outputAsset: false, writeToDisk: { filename }, }) ); } return config; }, }; ================================================ FILE: examples/with-loadable-components/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-loadable-components/src/App.js ================================================ import "./App.css"; import React from "react"; import loadable from "@loadable/component"; const Header = loadable(() => import("./Header")); const Body = loadable(() => import("./Body")); const Footer = loadable(() => import("./Footer")); const App = () => (

Welcome to the Razzle

); export default App; ================================================ FILE: examples/with-loadable-components/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-loadable-components/src/Body.js ================================================ import React from "react"; import loadable from "@loadable/component"; const BodyPart = loadable(() => import("./BodyPart")); const Body = () => (
This is my Body
); export default Body; ================================================ FILE: examples/with-loadable-components/src/BodyPart.js ================================================ import React from 'react'; const BodyPart = () => This is an inner BodyPart; export default BodyPart; ================================================ FILE: examples/with-loadable-components/src/Footer.js ================================================ import React from 'react'; const Footer = () =>
This is my Footer
; export default Footer; ================================================ FILE: examples/with-loadable-components/src/Header.js ================================================ import React from 'react'; const Header = () =>
This is my Header
; export default Header; ================================================ FILE: examples/with-loadable-components/src/client.js ================================================ import React from "react"; import { hydrate } from "react-dom"; import { loadableReady } from "@loadable/component"; import App from "./App"; // Load all components needed before rendering loadableReady().then(() => { hydrate(, document.getElementById("root")); }); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-loadable-components/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-loadable-components/src/server.js ================================================ import App from "./App"; import React from "react"; import express from "express"; import { renderToString } from "react-dom/server"; import { ChunkExtractor, ChunkExtractorManager } from "@loadable/server"; import path from "path"; const server = express(); export const renderApp = async (req) => { // We create an extractor from the statsFile const extractor = new ChunkExtractor({ statsFile: path.resolve("build/loadable-stats.json"), // razzle client bundle entrypoint is client.js entrypoints: ["client"], }); const markup = renderToString( ); // collect script tags const scriptTags = extractor.getScriptTags(); // collect "preload/prefetch" links const linkTags = extractor.getLinkTags(); // collect style tags const styleTags = extractor.getStyleTags(); const html = // prettier-ignore ` Welcome to Razzle ${linkTags} ${styleTags}
${markup}
${scriptTags} `; return { html }; } server .disable("x-powered-by") .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get("/*", async (req, res, next) => { try { const { html } = await renderApp(req); res.send(html); } catch (error) { next(error); } }); export default server; ================================================ FILE: examples/with-loadable-components/src/static_export.js ================================================ import { renderApp } from './server'; export const render = async (req, res) => { const { html } = await renderApp(req); res.json({ html }); }; export const routes = () => { return ['/']; }; ================================================ FILE: examples/with-material-ui/README.md ================================================ # Razzle and Material UI Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-material-ui with-material-ui cd with-material-ui yarn start ``` ## Idea behind the example This is a basic example of how to use Material UI with razzle. ================================================ FILE: examples/with-material-ui/package.json ================================================ { "name": "razzle-examples-with-material-ui", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "@material-ui/core": "^4.9.11", "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "@material-ui/styles": "^4.11.3", "babel-preset-razzle": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "prop-types": "^15.7.2", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-material-ui/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-material-ui/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-material-ui/src/App.js ================================================ import "./App.css"; import React from "react"; import PropTypes from "prop-types"; import Paper from "@material-ui/core/Paper"; import Typography from "@material-ui/core/Typography"; import { makeStyles } from "@material-ui/core/styles"; const useStyles = makeStyles((theme) => ({ root: theme.mixins.gutters({ paddingTop: 16, paddingBottom: 16, margin: theme.spacing(3), }), })); const App = () => { const classes = useStyles(); return ( This is a sheet of paper. Paper can be used to build surface or other elements for your application. ); }; export default App; ================================================ FILE: examples/with-material-ui/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-material-ui/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import theme from './theme'; import { ThemeProvider } from '@material-ui/styles'; import App from './App'; hydrate( , document.getElementById('root'), () => { // [ReHydratation](https://github.com/cssinjs/jss/blob/master/docs/ssr.md) const jssStyles = document.getElementById('jss-ssr'); if (jssStyles && jssStyles.parentNode) jssStyles.parentNode.removeChild(jssStyles); } ); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-material-ui/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-material-ui/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import theme from './theme'; import { ServerStyleSheets, ThemeProvider } from '@material-ui/styles'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const sheets = new ServerStyleSheets(); const markup = renderToString( sheets.collect( ) ); const css = sheets.toString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')} ${css ? `` : ''}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-material-ui/src/theme.js ================================================ import { createMuiTheme } from '@material-ui/core/styles'; import { indigo, orange } from '@material-ui/core/colors'; // Configure Material UI theme const theme = createMuiTheme({ palette: { primary: indigo, accent: orange, type: 'light', }, }); export default theme; ================================================ FILE: examples/with-mdx/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-mdx/README.md ================================================ # MDX + Razzle ## How to use Create and start the example: ```bash npx create-razzle-app --example with-mdx with-mdx cd with-mdx yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle. It satisfies the entry points and uses the mdxjs to load markdown files as react components. [See documentation](https://mdxjs.com/getting-started/razzle) ================================================ FILE: examples/with-mdx/package.json ================================================ { "name": "razzle-examples-with-mdx", "version": "4.2.15", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1", "remark-emoji": "^2.1.0" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "razzle-plugin-mdx": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-mdx/razzle.config.js ================================================ 'use strict'; const emoji = require('remark-emoji'); module.exports = { plugins: [ { name: 'mdx', options: { mdPlugins: [emoji], }, }, ], }; ================================================ FILE: examples/with-mdx/src/App.js ================================================ import React from 'react'; import Doc from './example.md'; export default () => ; ================================================ FILE: examples/with-mdx/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-mdx/src/example.md ================================================ An h1 header ============ Paragraphs are separated by a blank line. 2nd paragraph. *Italic*, **bold**, and `monospace`. Itemized lists look like: * this one * that one * the other one Note that --- not considering the asterisk --- the actual text content starts at 4-columns in. > Block quotes are > written like so. > > They can span multiple paragraphs, > if you like. Use 3 dashes for an em-dash. Use 2 dashes for ranges (ex., "it's all in chapters 12--14"). Three dots ... will be converted to an ellipsis. Unicode is supported. ☺ An h2 header ------------ Here's a numbered list: 1. first item 2. second item 3. third item Note again how the actual text starts at 4 columns in (4 characters from the left side). Here's a code sample: # Let me re-iterate ... for i in 1 .. 10 { do-something(i) } As you probably guessed, indented 4 spaces. By the way, instead of indenting the block, you can use delimited blocks, if you like: ~~~ define foobar() { print "Welcome to flavor country!"; } ~~~ (which makes copying & pasting easier). You can optionally mark the delimited block for Pandoc to syntax highlight it: ~~~python import time # Quick, count to ten! for i in range(10): # (but not *too* quick) time.sleep(0.5) print(i) ~~~ ### An h3 header ### Now a nested list: 1. First, get these ingredients: * carrots * celery * lentils 2. Boil some water. 3. Dump everything in the pot and follow this algorithm: find wooden spoon uncover pot stir cover pot balance wooden spoon precariously on pot handle wait 10 minutes goto first step (or shut off burner when done) Do not bump wooden spoon or it will fall. Notice again how text always lines up on 4-space indents (including that last line which continues item 3 above). Here's a link to [a website](http://foo.bar), to a [local doc](local-doc.html), and to a [section heading in the current doc](#an-h2-header). Here's a footnote [^1]. [^1]: Some footnote text. Tables can look like this: Name Size Material Color ------------- ----- ------------ ------------ All Business 9 leather brown Roundabout 10 hemp canvas natural Cinderella 11 glass transparent Table: Shoes sizes, materials, and colors. (The above is the caption for the table.) Pandoc also supports multi-line tables: -------- ----------------------- Keyword Text -------- ----------------------- red Sunsets, apples, and other red or reddish things. green Leaves, grass, frogs and other things it's not easy being. -------- ----------------------- A horizontal rule follows. *** Here's a definition list: apples : Good for making applesauce. oranges : Citrus! tomatoes : There's no "e" in tomatoe. Again, text is indented 4 spaces. (Put a blank line between each term and its definition to spread things out more.) Here's a "line block" (note how whitespace is honored): | Line one | Line too | Line tree Inline math equation: $\omega = d\phi / dt$. Display math should get its own line like so: $$I = \int \rho R^{2} dV$$ And note that you can backslash-escape any punctuation characters which you wish to be displayed literally, ex.: \`foo\`, \*bar\*, etc. ================================================ FILE: examples/with-mdx/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-mdx/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-module-federation/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-module-federation/README.md ================================================ # Razzle Module Federation Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-module-federation with-module-federation cd with-module-federation yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle with-module-federation. It satisfies the entry point `src/client.js` for the browser in both apps.. ================================================ FILE: examples/with-module-federation/basic-1/package.json ================================================ { "name": "razzle-examples-basic-1", "version": "4.0.0-canary.25", "license": "MIT", "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" } } ================================================ FILE: examples/with-module-federation/basic-1/public/index.html ================================================ <%= htmlWebpackPlugin.tags.headTags %> React App
<%= htmlWebpackPlugin.tags.bodyTags %> ================================================ FILE: examples/with-module-federation/basic-1/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-module-federation/basic-1/razzle.config.js ================================================ 'use strict'; const { ModuleFederationPlugin } = require("webpack").container; const path = require("path"); const deps = require("./package.json").dependencies; module.exports = { options: { buildType: 'spa', }, modifyWebpackConfig(opts) { const config = opts.webpackConfig; const url = opts.env.dev ? process.env.FEDERATED_URL_DEV : process.env.FEDERATED_URL; config.plugins.push( new ModuleFederationPlugin({ name: "app1", filename: "remoteEntry.js", remotes: { app2: `app2@${url}remoteEntry.js`, }, exposes: { "./Button": "./src/Button", }, shared: [ { ...deps, react: { // eager: true, singleton: true, requiredVersion: deps.react, }, "react-dom": { // eager: true, singleton: true, requiredVersion: deps["react-dom"], }, }, ], }) ) return config; }, }; ================================================ FILE: examples/with-module-federation/basic-1/src/App.js ================================================ import LocalButton from "./Button"; import React from "react"; const RemoteButton = React.lazy(() => import("app2/Button")); const App = () => (

Bi-Directional

App 1

); export default App; ================================================ FILE: examples/with-module-federation/basic-1/src/Button.js ================================================ import React from "react"; const style = { background: "#800", color: "#fff", padding: 12, }; const Button = () => ; export default Button; ================================================ FILE: examples/with-module-federation/basic-1/src/bootstrap.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-module-federation/basic-1/src/client.js ================================================ import("./bootstrap"); ================================================ FILE: examples/with-module-federation/basic-2/package.json ================================================ { "name": "razzle-examples-basic-2", "version": "4.0.0-canary.25", "license": "MIT", "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" } } ================================================ FILE: examples/with-module-federation/basic-2/public/index.html ================================================ <%= htmlWebpackPlugin.tags.headTags %> React App
<%= htmlWebpackPlugin.tags.bodyTags %> ================================================ FILE: examples/with-module-federation/basic-2/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-module-federation/basic-2/razzle.config.js ================================================ 'use strict'; const { ModuleFederationPlugin } = require("webpack").container; const path = require("path"); const deps = require("./package.json").dependencies; module.exports = { options: { buildType: 'spa', }, modifyWebpackConfig(opts) { const config = opts.webpackConfig; const url = opts.env.dev ? process.env.FEDERATED_URL_DEV : process.env.FEDERATED_URL; config.plugins.push( new ModuleFederationPlugin({ name: "app2", filename: "remoteEntry.js", remotes: { app1: `app1@${url}remoteEntry.js`, }, exposes: { "./Button": "./src/Button", }, shared: [ { ...deps, react: { // eager: true, singleton: true, requiredVersion: deps.react, }, "react-dom": { // eager: true, singleton: true, requiredVersion: deps["react-dom"], }, }, ], }) ) return config; }, }; ================================================ FILE: examples/with-module-federation/basic-2/src/App.js ================================================ import LocalButton from "./Button"; import React from "react"; const RemoteButton = React.lazy(() => import("app1/Button")); const App = () => (

Bi-Directional

App 2

); export default App; ================================================ FILE: examples/with-module-federation/basic-2/src/Button.js ================================================ import React from "react"; const style = { background: "#00c", color: "#fff", padding: 12, }; const Button = () => ; export default Button; ================================================ FILE: examples/with-module-federation/basic-2/src/bootstrap.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-module-federation/basic-2/src/client.js ================================================ import("./bootstrap"); ================================================ FILE: examples/with-module-federation/package.json ================================================ { "private": true, "name": "razzle-examples-with-module-federation", "version": "4.2.15", "license": "MIT", "scripts": { "start-1": "cross-env RAZZLE_APP_PATH=basic-1 razzle start", "build-1": "cross-env RAZZLE_APP_PATH=basic-1 razzle build", "test-1": "cross-env RAZZLE_APP_PATH=basic-1 razzle test --env=jsdom", "start:prod-1": "cross-env RAZZLE_APP_PATH=basic-1 PORT=3000 NODE_ENV=production serve -s basic-1/build/public", "start-2": "cross-env RAZZLE_APP_PATH=basic-2 razzle start", "build-2": "cross-env RAZZLE_APP_PATH=basic-2 razzle build", "test-2": "cross-env RAZZLE_APP_PATH=basic-2 razzle test --env=jsdom", "start:prod-2": "cross-env RAZZLE_APP_PATH=basic-2 PORT=3001 NODE_ENV=production serve -s basic-2/build/public", "start": "concurrently \"yarn start-1\" \"yarn start-2\"", "start:prod": "concurrently \"yarn start:prod-1\" \"yarn start:prod-2\"", "build": "concurrently \"yarn build-1 --noninteractive\" \"yarn build-2 --noninteractive\"" }, "workspaces": [ "basic-1", "basic-2" ], "devDependencies": { "concurrently": "^5.3.0", "cross-env": "^7.0.3", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^5.2.0", "webpack": "^5.24.0", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" }, "razzle_meta": { "forceWebpack": true } } ================================================ FILE: examples/with-monorepo/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-monorepo/README.md ================================================ # Razzle Monorepo Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-monorepo with-monorepo cd with-monorepo yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle in a monorepo. It satisfies the entry points `src/index.js` for the server and `src/client.js` for the browser in both apps. ================================================ FILE: examples/with-monorepo/basic-1/package.json ================================================ { "name": "razzle-examples-basic-1", "version": "4.0.0-canary.25", "license": "MIT", "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" } } ================================================ FILE: examples/with-monorepo/basic-1/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-monorepo/basic-1/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-monorepo/basic-1/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-monorepo/basic-1/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-monorepo/basic-1/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-monorepo/basic-1/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-monorepo/basic-1/src/server.js ================================================ import path from 'path'; import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-monorepo/basic-2/package.json ================================================ { "name": "razzle-examples-basic-2", "version": "4.0.0-canary.25", "license": "MIT", "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" } } ================================================ FILE: examples/with-monorepo/basic-2/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-monorepo/basic-2/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-monorepo/basic-2/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-monorepo/basic-2/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-monorepo/basic-2/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-monorepo/basic-2/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-monorepo/basic-2/src/server.js ================================================ import path from 'path'; import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-monorepo/package.json ================================================ { "private": true, "name": "razzle-examples-with-monorepo", "version": "4.2.15", "license": "MIT", "scripts": { "start-1": "cross-env RAZZLE_APP_PATH=basic-1 razzle start", "build-1": "cross-env RAZZLE_APP_PATH=basic-1 razzle build", "test-1": "cross-env RAZZLE_APP_PATH=basic-1 razzle test --env=jsdom", "start:prod-1": "cross-env RAZZLE_APP_PATH=basic-1 NODE_ENV=production node basic-1/build/server.js", "start-2": "cross-env RAZZLE_APP_PATH=basic-2 razzle start", "build-2": "cross-env RAZZLE_APP_PATH=basic-2 razzle build", "test-2": "cross-env RAZZLE_APP_PATH=basic-2 razzle test --env=jsdom", "start:prod-2": "cross-env RAZZLE_APP_PATH=basic-2 NODE_ENV=production node basic-2/build/server.js", "start": "concurrently \"yarn start-1\" \"yarn start-2\"", "start:prod": "concurrently \"yarn start:prod-1\" \"yarn start:prod-2\"", "build": "concurrently \"yarn build-1 --noninteractive\" \"yarn build-2 --noninteractive\"" }, "workspaces": [ "basic-1", "basic-2" ], "devDependencies": { "concurrently": "^5.3.0", "cross-env": "^7.0.3", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-monorepo-without-workspaces/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-monorepo-without-workspaces/README.md ================================================ # Razzle Monorepo without workspaces Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-monorepo-without-workspaces with-monorepo-without-workspaces cd with-monorepo-without-workspaces yarn start ``` ## Idea behind the example This is similar to the monorepo example, but adapted for the case where you want to build multiple separate applications that share the same dependencies (and therefore share the same package.json in the root). ================================================ FILE: examples/with-monorepo-without-workspaces/basic-1/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-monorepo-without-workspaces/basic-1/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-monorepo-without-workspaces/basic-1/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-monorepo-without-workspaces/basic-1/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-monorepo-without-workspaces/basic-1/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-monorepo-without-workspaces/basic-1/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-monorepo-without-workspaces/basic-1/src/server.js ================================================ import path from 'path'; import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-monorepo-without-workspaces/basic-2/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-monorepo-without-workspaces/basic-2/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-monorepo-without-workspaces/basic-2/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-monorepo-without-workspaces/basic-2/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-monorepo-without-workspaces/basic-2/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-monorepo-without-workspaces/basic-2/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-monorepo-without-workspaces/basic-2/src/server.js ================================================ import path from 'path'; import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-monorepo-without-workspaces/package.json ================================================ { "private": true, "name": "razzle-examples-with-monorepo-without-workspaces", "version": "4.2.15", "license": "MIT", "scripts": { "start-1": "cross-env RAZZLE_APP_PATH=basic-1 razzle start", "build-1": "cross-env RAZZLE_APP_PATH=basic-1 razzle build", "test-1": "cross-env RAZZLE_APP_PATH=basic-1 razzle test --env=jsdom", "start:prod-1": "cross-env RAZZLE_APP_PATH=basic-1 NODE_ENV=production node basic-1/build/server.js", "start-2": "cross-env RAZZLE_APP_PATH=basic-2 razzle start", "build-2": "cross-env RAZZLE_APP_PATH=basic-2 razzle build", "test-2": "cross-env RAZZLE_APP_PATH=basic-2 razzle test --env=jsdom", "start:prod-2": "cross-env RAZZLE_APP_PATH=basic-2 NODE_ENV=production node basic-2/build/server.js", "start": "concurrently \"yarn start-1\" \"yarn start-2\"", "start:prod": "concurrently \"yarn start:prod-1\" \"yarn start:prod-2\"", "build": "concurrently \"yarn build-1 --noninteractive\" \"yarn build-2 --noninteractive\"" }, "devDependencies": { "concurrently": "^5.3.0", "cross-env": "^7.0.3", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2", "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" } } ================================================ FILE: examples/with-now/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-now/README.md ================================================ # Razzle Now Deployment example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-now with-now cd with-now yarn start ``` ### Setup Now: [Now](https://zeit.co/now) manages app deployments with a [desktop](https://zeit.co/download) app or [CLI](https://zeit.co/download#now-cli). * You can download either the [desktop](https://zeit.co/download) (ships and installs the CLI as well) or just the [CLI](https://zeit.co/download#now-cli) * Or install only the CLI directly using: `npm install -g now` * Create a Now [account](https://zeit.co/signup) * Authenticate in the desktop app or CLI with `now login` ### Deploy: * Deploy using `now` in the root of your app. * Open your [Dashboard](https://zeit.co/dashboard/deployments) and test your deployment * Note: on the free plan your deployment and logs will be **_publicly visible_** #### Additional Configuration: * Additional build, deployment, and config steps available: [Zeit/Now](https://zeit.co/now#frequently-asked-questions) ## Idea behind the example This is a basic example of how to use razzle and deploy to [Now](https://zeit.co/now). ================================================ FILE: examples/with-now/package.json ================================================ { "name": "razzle-examples-with-now", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js", "now-start": "yarn start:prod" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-now/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-now/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-now/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-now/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-now/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-now/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-now/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-now-v2/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-now-v2/README.md ================================================ # Razzle Now v2 Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-now-v2 with-now-v2 cd with-now-v2 yarn start ``` Install now: ``` npm i -g now ``` Build and deploy: ```bash yarn build now ``` Open the link written in the console. ## Idea behind the example Take a look at `now.json`. We are uploading the result of the razzle build, and setting up the routes for the app entry point and all static resources. ```json { "version": 2, "name": "example", "builds": [ { "src": "build/public/**", "use": "@now/static" }, { "src": "build/server.js", "use": "@now/node-server" } ], "routes": [ { "src": "/assets.json", "dest": "build/assets.json" }, { "src": "/favicon.ico", "dest": "build/public/favicon.ico" }, { "src": "/robots.txt", "dest": "build/public/robots.txt" }, { "src": "/static/(.*)", "dest": "build/public/static/$1" }, { "src": "/(.*)", "dest": "build/server.js" } ], "env": { "NODE_ENV": "production" } } ``` We are also setting the `NODE_ENV` environment variable. Most likely, your app will use other environment variables, beware you should not commit secrets like api keys and others into your repository. Take a look at now's documentation to understand what you should do in such cases. ## Documentation * [Zeit Now v2 Documentation](https://zeit.co/docs/v2/) * [@now/node-server](https://zeit.co/docs/v2/deployments/official-builders/node-js-server-now-node-server/) * [Environment Variables and Secrets](https://zeit.co/docs/v2/deployments/environment-variables-and-secrets/) ================================================ FILE: examples/with-now-v2/now.json ================================================ { "version": 2, "builds": [{ "src": "build/server.js", "use": "@now/node" }, { "src": "build/public/**/*", "use": "@now/static" } ], "routes": [{ "src": "/static/(.*)", "dest": "build/public/static/$1" }, { "src": "/favicon.ico", "dest": "favicon.ico" }, { "src": "/robots.txt", "dest": "robots.txt" }, { "src": "/(.*)", "dest": "build/server.js" } ], "env": { "NODE_ENV": "production" } } ================================================ FILE: examples/with-now-v2/package.json ================================================ { "name": "razzle-examples-now-v2", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "now-build": "razzle build", "now-start": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-now-v2/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-now-v2/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-now-v2/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-now-v2/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-now-v2/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-now-v2/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-now-v2/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-polka/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-polka/README.md ================================================ # Razzle Polka Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-polka with-polka cd with-polka yarn start ``` ## Idea behind the example An example of how to use a custom, express middleware-compatible server like [polka](https://github.com/lukeed/polka) with razzle. It satisfies the entry points `src/index.js` for the server and and `src/client.js` for the browser. HMR works for server-side changes too by creating new instances of the polka server handler. ================================================ FILE: examples/with-polka/package.json ================================================ { "name": "razzle-examples-with-polka", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "polka": "^0.5.2", "react": "^17.0.1", "react-dom": "^17.0.1", "serve-static": "^1.14.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-polka/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-polka/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-polka/src/App.js ================================================ import './App.css'; import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-polka/src/App.test.js ================================================ import App from './App'; import React from 'react'; import ReactDOM from 'react-dom'; describe('', () => { test('renders without exploding', () => { const div = document.createElement('div'); ReactDOM.render(, div); }); }); ================================================ FILE: examples/with-polka/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-polka/src/index.js ================================================ import http from "http"; let app = require("./server").default; const server = http.createServer(app); let currentApp = app; server.listen(process.env.PORT || 3000, (error) => { if (error) { console.log(error); } console.log("🚀 started"); }); if (module.hot) { console.log("✅ Server-side HMR Enabled!"); module.hot.accept("./server", () => { console.log("🔁 HMR Reloading `./server`..."); try { app = require("./server").default; server.removeListener("request", currentApp); server.on("request", app); currentApp = app; } catch (error) { console.error(error); } }); } ================================================ FILE: examples/with-polka/src/server.js ================================================ import App from './App'; import React from 'react'; import polka from 'polka'; import serve from 'serve-static'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; export default polka() .use(serve(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.end(html); }).handler; ================================================ FILE: examples/with-preact/.babelrc ================================================ { "presets": [ "razzle/babel" ], "plugins": [ [ "@babel/plugin-transform-react-jsx", { "pragma": "h" } ] ] } ================================================ FILE: examples/with-preact/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local cache ================================================ FILE: examples/with-preact/README.md ================================================ # Razzle Preact Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-preact with-preact cd with-preact yarn start ``` ## Idea behind the example This shows how to setup [Preact](https://github.com/developit/preact) with Razzle. Here is a list of changes from Razzle's base template: 1. Install `babel-plugin-transform-react-jsx` as a devDependency. 2. Extend Razzle's babel config with a custom `.babelrc` 3. Install `preact` and `preact-render-to-string` 4. Remove `react`, `react-dom`, `react-router-dom` entirely 5. Update `server.js` to use `preact-render-to-string`'s `render` function. Also remove the `
` element from our html template since Preact can render to the body. ================================================ FILE: examples/with-preact/package.json ================================================ { "name": "razzle-examples-with-preact", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "preact": "^10.4.1", "preact-render-to-string": "^5.1.6", "react": "^17.0.1" }, "devDependencies": { "@prefresh/babel-plugin": "^0.2.0", "@prefresh/webpack": "^2.0.0", "@babel/core": "^7.12.10", "@babel/plugin-transform-react-jsx": "^7.9.4", "babel-preset-razzle": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "webpack": "^5.19.0", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-preact/public/robots.txt ================================================ User-agent: * Disallow: /api/ Disallow: /publicapi/ Disallow: /query/ ================================================ FILE: examples/with-preact/razzle.config.js ================================================ 'use strict'; const Prefresh = require('@prefresh/webpack'); module.exports = { experimental: { reactRefresh: false, }, modifyWebpackConfig(opts) { const { target, dev } = opts.env; const { webpackConfig: config } = opts; if (target !== 'node' && dev) { const jsRule = config.module.rules.find(loaderEntry => String(loaderEntry.test).includes('(js|jsx|mjs|ts|tsx)') ); const babelLoader = jsRule.use.find(useEntry => useEntry.loader.includes('babel-loader') ); if (babelLoader.options.plugins) { babelLoader.options.plugins.unshift('@prefresh/babel-plugin'); } else { babelLoader.options.plugins = ['@prefresh/babel-plugin']; } config.plugins.unshift(new Prefresh()); } return config; }, }; ================================================ FILE: examples/with-preact/src/App.js ================================================ import { h } from 'preact'; import { useState } from 'preact/hooks'; import PreactLogo from './preact.svg'; /** @jsx h */ const App = () => { const [count, setCount] = useState(0); return (
Preact Logo Hello Preact!

Count: {count}

); }; export default App; ================================================ FILE: examples/with-preact/src/client.js ================================================ import { h, hydrate } from "preact"; import App from "./App"; /** @jsx h */ hydrate(, document.body, document.body.firstElementChild); ================================================ FILE: examples/with-preact/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-preact/src/server.js ================================================ import App from './App'; import express from 'express'; import { h } from 'preact'; // eslint-disable-line import render from 'preact-render-to-string'; /** @jsx h */ const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = render(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-promise-config/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.local .env.development.local .env.test.local .env.production.local ================================================ FILE: examples/with-promise-config/README.md ================================================ # Razzle Custom Promise Configuration Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-promise-config with-promise-config cd with-promise-config yarn start ``` ## Idea behind the example This example demonstrates how to use a `razzle.config.js` file to modify Razzle's underlying configuration using a promise. It modifies the name of the server's output file in production (`razzle build`). Note that this file is not transpiled, and so you must write it with vanilla Node.js-compatible JavaScript. ```js // razzle.config.js 'use strict'; module.exports = { modifyWebpackConfig(opts) { const config = opts.webpackConfig; return new Promise((resolve) => { setTimeout(() => { // Change the name of the server output file in production if (opts.env.target === 'node' && !opts.env.dev) { config.output.filename = 'custom.js'; } resolve(config); }, 10); }); }, }; ``` ================================================ FILE: examples/with-promise-config/package.json ================================================ { "name": "razzle-examples-with-promise-config", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/custom.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-promise-config/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-promise-config/razzle.config.js ================================================ 'use strict'; module.exports = { modifyWebpackConfig(opts) { const config = opts.webpackConfig; return new Promise((resolve) => { setTimeout(() => { // Change the name of the server output file in production if (opts.env.target === 'node' && !opts.env.dev) { config.output.filename = 'custom.js'; } resolve(config); }, 10); }); }, }; ================================================ FILE: examples/with-promise-config/src/App.js ================================================ import React from 'react'; const App = () =>
Welcome to Razzle.
; export default App; ================================================ FILE: examples/with-promise-config/src/client.js ================================================ import React from 'react'; import { hydrate } from 'react-dom'; import App from './App'; hydrate(, document.getElementById('root')); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-promise-config/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-promise-config/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { const markup = renderToString(); const html = // prettier-ignore ` Welcome to Razzle ${cssLinksFromAssets(assets, 'client')}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-react-native-web/.babelrc ================================================ { "presets": ["razzle/babel"], "plugins": [["react-native-web", { "commonjs": true }]] } ================================================ FILE: examples/with-react-native-web/README.md ================================================ # Razzle React Native Web Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-react-native-web with-react-native-web cd with-react-native-web yarn start ``` ## Idea behind the example This example demonstrates how to use [React Native Web](https://github.com/necolas/react-native-web) with Razzle. Relative to the basic Razzle example, there are some noteworthy modifications. First, we add `react-native-web` to dependencies and `babel-plugin-react-native-web` to dev dependencies. ``` yarn add react-native-web yarn add babel-plugin-react-native-web --dev ``` Next we add a custom `.babelrc` file to the root our of project as follows. As described in the documentation, we include Razzle's default babel plugin AND the custom react-native-web plugin. ```json { "presets": ["razzle/babel"], "plugins": ["react-native-web"] } ``` In our code, we modify our `src/client.js` as per the RN Web docs. Notice how we are _not_ calling `ReactDOM.hydrate()` ourselves, as this is done by RN Web. ```js // ./src/client.js import React from 'react'; import App from './App'; import { AppRegistry } from 'react-native'; // register the app AppRegistry.registerComponent('App', () => App); AppRegistry.runApplication('App', { initialProps: {}, rootTag: document.getElementById('root'), }); // Allow HMR to work if (module.hot) { module.hot.accept(); } ``` In `src/server.js`, we also can basically copy and paste from the RN Web docs. Important note: RN Web handles CSS-in-js for us, so we remove `assets.client.css` `` tag from our HTML string template and replace it with just the `css` variable we get from RN Web. ```js // ./src/server.js import App from './App'; import express from 'express'; import ReactDOMServer from 'react-dom/server'; import { AppRegistry } from 'react-native'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { // register the app AppRegistry.registerComponent('App', () => App); // prerender the app const { element, getStyleElement } = AppRegistry.getApplication('App', {}); // first the element const html = ReactDOMServer.renderToString(element); // then the styles const css = ReactDOMServer.renderToStaticMarkup(getStyleElement()); res.send( ` Welcome to Razzle ${css} ${ process.env.NODE_ENV === 'production' ? `` : `` }
${html}
` ); }); export default server; ``` ### Webpack setup Like [create-react-app](https://github.com/facebook/create-react-app), Razzle already takes care of aliasing `react-native` to `react-native-web` with webpack for you. So we don't need to mess with that. However, since we are using RN Web for all our CSS, we can get a significant Webpack #perf boost during development and build tasks if we **remove all the built-in CSS loaders from Razzle**. To do this, we create a file called `razzle.config.js` in our root directory and use the `modify` function. Notice that we are using regex tests to sniff which Webpack module rules we should filter out. This approach is _significantly_ better than just removing a rule at a specific index of the rules array, which could change between Razzle releases. ```js 'use strict'; module.exports = { modify(config, { target, dev }, webpack) { // Since RN web takes care of CSS, we should remove it for a #perf boost config.module.rules = config.module.rules .filter( rule => !(rule.test && rule.test.exec && rule.test.exec('./something.css')) ) .filter( rule => !( rule.test && rule.test.exec && rule.test.exec('./something.module.css') ) ); return config; }, }; ``` ================================================ FILE: examples/with-react-native-web/package.json ================================================ { "name": "razzle-examples-with-react-native-web", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1", "react-native-web": "0.15.0" }, "devDependencies": { "babel-plugin-react-native-web": "0.15.0", "babel-preset-razzle": "4.2.15", "extract-text-webpack-plugin": "^3.0.2", "mini-css-extract-plugin": "^0.9.0", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "react-native": "^0.63.4", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-react-native-web/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-react-native-web/razzle.config.js ================================================ 'use strict'; module.exports = { modifyWebpackConfig(opts) { const config = opts.webpackConfig; // Since RN web takes care of CSS, we should remove it for a #perf boost config.module.rules = config.module.rules .filter( rule => !(rule.test && rule.test.exec && rule.test.exec('./something.css')) ) .filter( rule => !( rule.test && rule.test.exec && rule.test.exec('./something.module.css') ) ); return config; }, }; ================================================ FILE: examples/with-react-native-web/src/App.js ================================================ import React from 'react'; import { StyleSheet, Text, View } from 'react-native'; class App extends React.Component { render() { return ( Hello, world! ); } } const styles = StyleSheet.create({ box: { padding: 10 }, text: { fontWeight: 'bold' }, }); export default App; ================================================ FILE: examples/with-react-native-web/src/client.js ================================================ /* eslint-disable */ import React from 'react'; import App from './App'; import { AppRegistry } from 'react-native'; // register the app AppRegistry.registerComponent('App', () => App); AppRegistry.runApplication('App', { initialProps: {}, rootTag: document.getElementById('root'), }); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-react-native-web/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-react-native-web/src/server.js ================================================ import App from './App'; import express from 'express'; import ReactDOMServer from 'react-dom/server'; import { AppRegistry } from 'react-native'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const cssLinksFromAssets = (assets, entrypoint) => { return assets[entrypoint] ? assets[entrypoint].css ? assets[entrypoint].css.map(asset=> `` ).join('') : '' : ''; }; const jsScriptTagsFromAssets = (assets, entrypoint, extra = '') => { return assets[entrypoint] ? assets[entrypoint].js ? assets[entrypoint].js.map(asset=> `` ).join('') : '' : ''; }; export const renderApp = (req, res) => { // register the app AppRegistry.registerComponent('App', () => App); // prerender the app const { element, getStyleElement } = AppRegistry.getApplication('App', {}); // first the element const markup = ReactDOMServer.renderToString(element); // then the styles const css = ReactDOMServer.renderToStaticMarkup(getStyleElement()); const html = // prettier-ignore ` Welcome to Razzle ${css}
${markup}
${jsScriptTagsFromAssets(assets, 'client', ' defer crossorigin')} `; return { html }; }; const server = express(); server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html } = renderApp(req, res); res.send(html); }); export default server; ================================================ FILE: examples/with-react-router/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-react-router/README.md ================================================ # Razzle x React Router ## How to use Create and start the example: ```bash npx create-razzle-app --example with-react-router with-react-router cd with-react-router yarn start ``` This example can also be exported as a static website. To try it out: ```bash yarn build yarn export yarn start:static ``` Then open up http://localhost:5000/ in your browser. ## Idea behind the example This is a basic, bare-bones example of how to use Razzle and React Router. ================================================ FILE: examples/with-react-router/package.json ================================================ { "name": "razzle-examples-with-react-router", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "export": "razzle export", "test": "razzle test --env=jsdom", "start:static": "serve -s build/public", "start:prod": "NODE_ENV=production node build/server.js" }, "dependencies": { "express": "^4.17.1", "react": "^17.0.1", "react-dom": "^17.0.1", "react-router-dom": "^5.1.2" }, "devDependencies": { "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "serve": "^11.3.2", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "webpack-dev-server": "^3.11.2" } } ================================================ FILE: examples/with-react-router/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-react-router/src/About.js ================================================ import React from "react"; const About = () =>

about

; export default About; ================================================ FILE: examples/with-react-router/src/App.css ================================================ body { margin: 0; padding: 0; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; } ================================================ FILE: examples/with-react-router/src/App.js ================================================ import { Route, Switch } from "react-router-dom"; import Home from "./Home"; import About from "./About"; import "./App.css"; import React from "react"; const App = () => { return ( <> ); }; export default App; ================================================ FILE: examples/with-react-router/src/App.test.js ================================================ import App from "./App"; import React from "react"; import ReactDOM from "react-dom"; import { BrowserRouter } from "react-router-dom"; describe("", () => { test("renders without exploding", () => { const div = document.createElement("div"); ReactDOM.render( , div ); }); }); ================================================ FILE: examples/with-react-router/src/Home.js ================================================ import React from "react"; import { Link } from "react-router-dom"; const Home = () => { return ( <>

Welcome to Razzle.

About ); }; export default Home; ================================================ FILE: examples/with-react-router/src/client.js ================================================ import React from "react"; import { hydrate } from "react-dom"; import { BrowserRouter } from "react-router-dom"; import App from "./App"; hydrate( , document.getElementById("root") ); if (module.hot) { module.hot.accept(); } ================================================ FILE: examples/with-react-router/src/index.js ================================================ import express from 'express'; let app = require('./server').default; if (module.hot) { module.hot.accept('./server', function() { console.log('🔁 HMR Reloading `./server`...'); try { app = require('./server').default; } catch (error) { console.error(error); } }); console.info('✅ Server-side HMR Enabled!'); } const port = process.env.PORT || 3000; export default express() .use((req, res) => app.handle(req, res)) .listen(port, function(err) { if (err) { console.error(err); return; } console.log(`> Started on port ${port}`); }); ================================================ FILE: examples/with-react-router/src/server.js ================================================ import App from './App'; import React from 'react'; import express from 'express'; import { renderToString } from 'react-dom/server'; import { StaticRouter } from 'react-router-dom'; const assets = require(process.env.RAZZLE_ASSETS_MANIFEST); const server = express(); export const renderApp = (req, res) => { const context = {}; const markup = renderToString( ); const html = // prettier-ignore ` Welcome to Razzle ${ assets.client.css ? `` : '' }
${markup}
`; return { html, context }; }; server .disable('x-powered-by') .use(express.static(process.env.RAZZLE_PUBLIC_DIR)) .get('/*', (req, res) => { const { html, context } = renderApp(req, res); if (context.url) { // Somewhere a `` was rendered return res.redirect(301, context.url); } res.send(html); }); export default server; ================================================ FILE: examples/with-react-router/src/static_export.js ================================================ import { renderApp } from './server'; export const render = (req, res) => { const { html } = renderApp(req, res); res.json({ html }); }; export const routes = () => { return ['/', '/about']; }; ================================================ FILE: examples/with-react-server-components/.gitignore ================================================ logs *.log npm-debug.log* .DS_Store coverage node_modules build public/static .env.*.local ================================================ FILE: examples/with-react-server-components/README.md ================================================ # Razzle With React Server Components Example ## How to use Create and start the example: ```bash npx create-razzle-app --example with-react-server-components with-react-server-components cd with-react-server-components yarn start ``` ## Idea behind the example This is a basic, bare-bones example of how to use razzle With react server components. It satisfies the entry points `src/index.js` for the server and and `src/client.js` for the browser. ================================================ FILE: examples/with-react-server-components/babel.config.js ================================================ module.exports = (api) => { api.cache.using(() => process.env.NODE_ENV); // const enableFastRefresh = !api.env('production') && !api.env('test'); const enableFastRefresh = false; return { presets: [ [ '@babel/preset-react', { runtime: 'automatic', }, ], [ '@babel/preset-env', { targets: { node: 'current', }, }, ], '@babel/preset-typescript', ], plugins: [ '@babel/plugin-proposal-class-properties', '@babel/plugin-proposal-export-default-from', '@babel/plugin-proposal-export-namespace-from', '@babel/plugin-proposal-nullish-coalescing-operator', '@babel/plugin-proposal-optional-chaining', ], }; }; ================================================ FILE: examples/with-react-server-components/notes/.gitkeep ================================================ ================================================ FILE: examples/with-react-server-components/notes/1.md ================================================ This is an example note. It contains **Markdown**! ================================================ FILE: examples/with-react-server-components/notes/2.md ================================================ It's very easy to make some words **bold** and other words *italic* with Markdown. You can even [link to React's website!](https://www.reactjs.org). ================================================ FILE: examples/with-react-server-components/notes/3.md ================================================ You can write all kinds of [amazing](https://en.wikipedia.org/wiki/The_Amazing) notes in this app! These note live on the server in the `notes` folder. ![This app is powered by React](https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/React_Native_Logo.png/800px-React_Native_Logo.png) ================================================ FILE: examples/with-react-server-components/notes/4.md ================================================ It was an excellent note.54545 ================================================ FILE: examples/with-react-server-components/package.json ================================================ { "name": "razzle-examples-with-react-server-components", "version": "4.2.15", "license": "MIT", "scripts": { "start": "razzle start", "build": "razzle build", "test": "razzle test --env=jsdom", "start:prod": "NODE_ENV=production babel-node --extensions \\\".es6,.js,.es,.jsx,.mjs,.ts,.tsx\\\" --conditions=react-server build/server.server", "plugin": "babel --extensions \\\".es6,.js,.es,.jsx,.mjs,.ts,.tsx\\\" --watch plugin/**.ts --out-dir ./plugin", "seed": "node ./scripts/seed.js" }, "dependencies": { "babel-preset-react-app": "10.0.0", "better-sqlite3": "^7.1.2", "date-fns": "^2.16.1", "excerpts": "^0.0.3", "express": "^4.17.1", "marked": "^1.2.5", "react": "^17.0.1", "react-dom": "^17.0.1", "react-error-boundary": "^3.1.0", "react-fetch": "0.0.0-experimental-3310209d0", "react-fs": "0.0.0-experimental-3310209d0", "react-server-dom-webpack": "0.0.0-experimental-3310209d0", "resolve": "1.12.0", "rimraf": "^3.0.2", "sanitize-html": "^2.2.0" }, "devDependencies": { "@babel/cli": "7.12.10", "@babel/node": "7.12.10", "@babel/core": "7.12.3", "cross-env": "^7.0.3", "webpack-stats-plugin": "^1.0.3", "razzle": "4.2.15", "razzle-dev-utils": "4.2.15", "mini-css-extract-plugin": "^0.9.0", "html-webpack-plugin": "^4.5.2", "webpack": "^4.44.1", "babel-preset-razzle": "4.2.15", "@babel/plugin-proposal-class-properties": "7.12.1", "@babel/plugin-proposal-export-default-from": "7.12.1", "@babel/plugin-proposal-export-namespace-from": "7.12.1", "@babel/plugin-proposal-nullish-coalescing-operator": "7.12.1", "@babel/plugin-proposal-optional-chaining": "7.12.7", "@babel/plugin-transform-flow-strip-types": "7.12.10", "@babel/plugin-transform-react-jsx-source": "7.12.1", "@babel/preset-react": "7.12.10", "@babel/preset-typescript": "7.12.7", "@types/babel__core": "7.1.12", "@types/compression": "^1.7.0", "@types/concurrently": "5.2.1", "@types/express": "^4.17.9", "@types/jest": "26.0.19", "@types/marked": "^1.2.1", "@types/prettier": "2.1.6", "@types/react": "17.0.0", "@types/react-dom": "17.0.0", "@types/rimraf": "3.0.0", "@types/sanitize-html": "^1.27.0", "@types/webpack": "4.41.25", "@types/webpack-node-externals": "2.5.0", "prettier": "2.2.1", "rimraf": "3.0.2", "typescript": "4.1.3", "webpack-dev-server": "^3.11.2" }, "razzle_meta": { "forceWebpack": true, "nohoist": [ "react", "react-dom", "react-fetch", "react-fs", "react-server-dom-webpack", "webpack" ] } } ================================================ FILE: examples/with-react-server-components/plugin/ReactFlightWebpackLoader.js ================================================ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = _default; // eslint-disable-next-line function _default(source) { let newSrc = "const MODULE_REFERENCE = Symbol.for('react.module.reference');\n"; // TODO - extract names (export names) using acorn, check ReactFlightWebpackNodeLoader const names = ['default']; for (let i = 0; i < names.length; i++) { const name = names[i]; if (name === 'default') { newSrc += 'export default '; } else { newSrc += 'export const ' + name + ' = '; } newSrc += '{ $$typeof: MODULE_REFERENCE, filepath: '; newSrc += `'file://${this.resourcePath}'`; newSrc += ', name: '; newSrc += JSON.stringify(name); newSrc += '};\n'; } console.log({ newSrc }); return newSrc; } ================================================ FILE: examples/with-react-server-components/plugin/ReactFlightWebpackLoader.ts ================================================ // eslint-disable-next-line export default function (source) { let newSrc = "const MODULE_REFERENCE = Symbol.for('react.module.reference');\n"; // TODO - extract names (export names) using acorn, check ReactFlightWebpackNodeLoader const names = ['default']; for (let i = 0; i < names.length; i++) { const name = names[i]; if (name === 'default') { newSrc += 'export default '; } else { newSrc += 'export const ' + name + ' = '; } newSrc += '{ $$typeof: MODULE_REFERENCE, filepath: '; newSrc += `'file://${this.resourcePath}'`; newSrc += ', name: '; newSrc += JSON.stringify(name); newSrc += '};\n'; } console.log({ newSrc, }); return newSrc; } ================================================ FILE: examples/with-react-server-components/plugin/ReactFlightWebpackNodeLoader.js ================================================ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.resolve = resolve; exports.getSource = getSource; exports.transformSource = transformSource; var _acorn = _interopRequireDefault(require("acorn")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ let warnedAboutConditionsFlag = false; let stashedGetSource = null; let stashedResolve = null; async function resolve(specifier, context, defaultResolve) { // We stash this in case we end up needing to resolve export * statements later. stashedResolve = defaultResolve; if (!context.conditions.includes('react-server')) { context = { ...context, conditions: [...context.conditions, 'react-server'] }; if (!warnedAboutConditionsFlag) { warnedAboutConditionsFlag = true; // eslint-disable-next-line react-internal/no-production-logging console.warn('You did not run Node.js with the `--conditions react-server` flag. ' + 'Any "react-server" override will only work with ESM imports.'); } } const resolved = await defaultResolve(specifier, context, defaultResolve); if (resolved.url.endsWith('.server.js')) { const parentURL = context.parentURL; if (parentURL && !parentURL.endsWith('.server.js')) { let reason; if (specifier.endsWith('.server.js')) { reason = `"${specifier}"`; } else { reason = `"${specifier}" (which expands to "${resolved.url}")`; } throw new Error(`Cannot import ${reason} from "${parentURL}". ` + 'By react-server convention, .server.js files can only be imported from other .server.js files. ' + 'That way nobody accidentally sends these to the client by indirectly importing it.'); } } return resolved; } async function getSource(url, context, defaultGetSource) { // We stash this in case we end up needing to resolve export * statements later. stashedGetSource = defaultGetSource; return defaultGetSource(url, context, defaultGetSource); } function addExportNames(names, node) { switch (node.type) { case 'Identifier': names.push(node.name); return; case 'ObjectPattern': for (let i = 0; i < node.properties.length; i++) addExportNames(names, node.properties[i]); return; case 'ArrayPattern': for (let i = 0; i < node.elements.length; i++) { const element = node.elements[i]; if (element) addExportNames(names, element); } return; case 'Property': addExportNames(names, node.value); return; case 'AssignmentPattern': addExportNames(names, node.left); return; case 'RestElement': addExportNames(names, node.argument); return; case 'ParenthesizedExpression': addExportNames(names, node.expression); return; } } function resolveClientImport(specifier, parentURL) { // Resolve an import specifier as if it was loaded by the client. This doesn't use // the overrides that this loader does but instead reverts to the default. // This resolution algorithm will not necessarily have the same configuration // as the actual client loader. It should mostly work and if it doesn't you can // always convert to explicit exported names instead. const conditions = ['node', 'import']; if (stashedResolve === null) { throw new Error('Expected resolve to have been called before transformSource'); } return stashedResolve(specifier, { conditions, parentURL }, stashedResolve); } async function loadClientImport(url, defaultTransformSource) { if (stashedGetSource === null) { throw new Error('Expected getSource to have been called before transformSource'); } // TODO: Validate that this is another module by calling getFormat. const { source } = await stashedGetSource(url, { format: 'module' }, stashedGetSource); return defaultTransformSource(source, { format: 'module', url }, defaultTransformSource); } async function parseExportNamesInto(transformedSource, names, parentURL, defaultTransformSource) { const { body } = _acorn.default.parse(transformedSource, { ecmaVersion: '2019', sourceType: 'module' }); for (let i = 0; i < body.length; i++) { const node = body[i]; switch (node.type) { case 'ExportAllDeclaration': if (node.exported) { addExportNames(names, node.exported); continue; } else { const { url } = await resolveClientImport(node.source.value, parentURL); const { source } = await loadClientImport(url, defaultTransformSource); if (typeof source !== 'string') { throw new Error('Expected the transformed source to be a string.'); } parseExportNamesInto(source, names, url, defaultTransformSource); continue; } case 'ExportDefaultDeclaration': names.push('default'); continue; case 'ExportNamedDeclaration': if (node.declaration) { if (node.declaration.type === 'VariableDeclaration') { const declarations = node.declaration.declarations; for (let j = 0; j < declarations.length; j++) { addExportNames(names, declarations[j].id); } } else { addExportNames(names, node.declaration.id); } } if (node.specificers) { const specificers = node.specificers; for (let j = 0; j < specificers.length; j++) { addExportNames(names, specificers[j].exported); } } continue; } } } async function transformSource(source, context, defaultTransformSource) { const transformed = await defaultTransformSource(source, context, defaultTransformSource); if (context.format === 'module' && context.url.endsWith('.client.js')) { const transformedSource = transformed.source; if (typeof transformedSource !== 'string') { throw new Error('Expected source to have been transformed to a string.'); } const names = []; await parseExportNamesInto(transformedSource, names, context.url, defaultTransformSource); let newSrc = "const MODULE_REFERENCE = Symbol.for('react.module.reference');\n"; for (let i = 0; i < names.length; i++) { const name = names[i]; if (name === 'default') { newSrc += 'export default '; } else { newSrc += 'export const ' + name + ' = '; } newSrc += '{ $$typeof: MODULE_REFERENCE, filepath: '; newSrc += JSON.stringify(context.url); newSrc += ', name: '; newSrc += JSON.stringify(name); newSrc += '};\n'; } return { source: newSrc }; } return transformed; } ================================================ FILE: examples/with-react-server-components/plugin/ReactFlightWebpackNodeLoader.ts ================================================ /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ import acorn from 'acorn'; type ResolveContext = { conditions: Array; parentURL: string | void; }; type ResolveFunction = ( string, ResolveContext, ResolveFunction, ) => { url: string } | Promise<{ url: string }>; type GetSourceContext = { format: string; }; type GetSourceFunction = ( string, GetSourceContext, GetSourceFunction, ) => Promise<{ source: Source }>; type TransformSourceContext = { format: string; url: string; }; type TransformSourceFunction = ( Source, TransformSourceContext, TransformSourceFunction, ) => Promise<{ source: Source }>; type Source = string | ArrayBuffer | Uint8Array; let warnedAboutConditionsFlag = false; let stashedGetSource: null | GetSourceFunction = null; let stashedResolve: null | ResolveFunction = null; export async function resolve( specifier: string, context: ResolveContext, defaultResolve: ResolveFunction, ): Promise<{ url: string }> { // We stash this in case we end up needing to resolve export * statements later. stashedResolve = defaultResolve; if (!context.conditions.includes('react-server')) { context = { ...context, conditions: [...context.conditions, 'react-server'], }; if (!warnedAboutConditionsFlag) { warnedAboutConditionsFlag = true; // eslint-disable-next-line react-internal/no-production-logging console.warn( 'You did not run Node.js with the `--conditions react-server` flag. ' + 'Any "react-server" override will only work with ESM imports.', ); } } const resolved = await defaultResolve(specifier, context, defaultResolve); if (resolved.url.endsWith('.server.js')) { const parentURL = context.parentURL; if (parentURL && !parentURL.endsWith('.server.js')) { let reason; if (specifier.endsWith('.server.js')) { reason = `"${specifier}"`; } else { reason = `"${specifier}" (which expands to "${resolved.url}")`; } throw new Error( `Cannot import ${reason} from "${parentURL}". ` + 'By react-server convention, .server.js files can only be imported from other .server.js files. ' + 'That way nobody accidentally sends these to the client by indirectly importing it.', ); } } return resolved; } export async function getSource( url: string, context: GetSourceContext, defaultGetSource: GetSourceFunction, ) { // We stash this in case we end up needing to resolve export * statements later. stashedGetSource = defaultGetSource; return defaultGetSource(url, context, defaultGetSource); } function addExportNames(names, node) { switch (node.type) { case 'Identifier': names.push(node.name); return; case 'ObjectPattern': for (let i = 0; i < node.properties.length; i++) addExportNames(names, node.properties[i]); return; case 'ArrayPattern': for (let i = 0; i < node.elements.length; i++) { const element = node.elements[i]; if (element) addExportNames(names, element); } return; case 'Property': addExportNames(names, node.value); return; case 'AssignmentPattern': addExportNames(names, node.left); return; case 'RestElement': addExportNames(names, node.argument); return; case 'ParenthesizedExpression': addExportNames(names, node.expression); return; } } function resolveClientImport( specifier: string, parentURL: string, ): { url: string } | Promise<{ url: string }> { // Resolve an import specifier as if it was loaded by the client. This doesn't use // the overrides that this loader does but instead reverts to the default. // This resolution algorithm will not necessarily have the same configuration // as the actual client loader. It should mostly work and if it doesn't you can // always convert to explicit exported names instead. const conditions = ['node', 'import']; if (stashedResolve === null) { throw new Error( 'Expected resolve to have been called before transformSource', ); } return stashedResolve(specifier, { conditions, parentURL }, stashedResolve); } async function loadClientImport( url: string, defaultTransformSource: TransformSourceFunction, ): Promise<{ source: Source }> { if (stashedGetSource === null) { throw new Error( 'Expected getSource to have been called before transformSource', ); } // TODO: Validate that this is another module by calling getFormat. const { source } = await stashedGetSource( url, { format: 'module' }, stashedGetSource, ); return defaultTransformSource( source, { format: 'module', url }, defaultTransformSource, ); } async function parseExportNamesInto( transformedSource: string, names: Array, parentURL: string, defaultTransformSource, ): Promise { const { body } = acorn.parse(transformedSource, { ecmaVersion: '2019', sourceType: 'module', }); for (let i = 0; i < body.length; i++) { const node = body[i]; switch (node.type) { case 'ExportAllDeclaration': if (node.exported) { addExportNames(names, node.exported); continue; } else { const { url } = await resolveClientImport( node.source.value, parentURL, ); const { source } = await loadClientImport( url, defaultTransformSource, ); if (typeof source !== 'string') { throw new Error('Expected the transformed source to be a string.'); } parseExportNamesInto(source, names, url, defaultTransformSource); continue; } case 'ExportDefaultDeclaration': names.push('default'); continue; case 'ExportNamedDeclaration': if (node.declaration) { if (node.declaration.type === 'VariableDeclaration') { const declarations = node.declaration.declarations; for (let j = 0; j < declarations.length; j++) { addExportNames(names, declarations[j].id); } } else { addExportNames(names, node.declaration.id); } } if (node.specificers) { const specificers = node.specificers; for (let j = 0; j < specificers.length; j++) { addExportNames(names, specificers[j].exported); } } continue; } } } export async function transformSource( source: Source, context: TransformSourceContext, defaultTransformSource: TransformSourceFunction, ): Promise<{ source: Source }> { const transformed = await defaultTransformSource( source, context, defaultTransformSource, ); if (context.format === 'module' && context.url.endsWith('.client.js')) { const transformedSource = transformed.source; if (typeof transformedSource !== 'string') { throw new Error('Expected source to have been transformed to a string.'); } const names = []; await parseExportNamesInto( transformedSource, names, context.url, defaultTransformSource, ); let newSrc = "const MODULE_REFERENCE = Symbol.for('react.module.reference');\n"; for (let i = 0; i < names.length; i++) { const name = names[i]; if (name === 'default') { newSrc += 'export default '; } else { newSrc += 'export const ' + name + ' = '; } newSrc += '{ $$typeof: MODULE_REFERENCE, filepath: '; newSrc += JSON.stringify(context.url); newSrc += ', name: '; newSrc += JSON.stringify(name); newSrc += '};\n'; } return { source: newSrc }; } return transformed; } ================================================ FILE: examples/with-react-server-components/plugin/ReactFlightWebpackNodeRegister.js ================================================ "use strict"; /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ const url = require('url'); // $FlowFixMe const Module = require('module'); module.exports = function register() { const MODULE_REFERENCE = Symbol.for('react.module.reference'); const proxyHandlers = { get: function (target, name, receiver) { switch (name) { // These names are read by the Flight runtime if you end up using the exports object. case '$$typeof': // These names are a little too common. We should probably have a way to // have the Flight runtime extract the inner target instead. return target.$$typeof; case 'filepath': return target.filepath; case 'name': return target.name; // We need to special case this because createElement reads it if we pass this // reference. case 'defaultProps': return undefined; case '__esModule': // Something is conditionally checking which export to use. We'll pretend to be // an ESM compat module but then we'll check again on the client. target.default = { $$typeof: MODULE_REFERENCE, filepath: target.filepath, // This a placeholder value that tells the client to conditionally use the // whole object or just the default export. name: '' }; return true; } let cachedReference = target[name]; if (!cachedReference) { cachedReference = target[name] = { $$typeof: MODULE_REFERENCE, filepath: target.filepath, name: name }; } return cachedReference; }, set: function () { throw new Error('Cannot assign to a client module from a server module.'); } }; require.extensions['.client.js'] = function (module, path) { const moduleId = url.pathToFileURL(path).href; const moduleReference = { $$typeof: MODULE_REFERENCE, filepath: moduleId, name: '*' // Represents the whole object instead of a particular import. }; module.exports = new Proxy(moduleReference, proxyHandlers); }; const originalResolveFilename = Module._resolveFilename; Module._resolveFilename = function (request, parent, isMain, options) { const resolved = originalResolveFilename.apply(this, arguments); if (resolved.endsWith('.server.js')) { if (parent && parent.filename && !parent.filename.endsWith('.server.js')) { let reason; if (request.endsWith('.server.js')) { reason = `"${request}"`; } else { reason = `"${request}" (which expands to "${resolved}")`; } throw new Error(`Cannot import ${reason} from "${parent.filename}". ` + 'By react-server convention, .server.js files can only be imported from other .server.js files. ' + 'That way nobody accidentally sends these to the client by indirectly importing it.'); } } return resolved; }; }; ================================================ FILE: examples/with-react-server-components/plugin/ReactFlightWebpackNodeRegister.ts ================================================ /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ const url = require('url'); // $FlowFixMe const Module = require('module'); module.exports = function register() { const MODULE_REFERENCE = Symbol.for('react.module.reference'); const proxyHandlers = { get: function (target, name, receiver) { switch (name) { // These names are read by the Flight runtime if you end up using the exports object. case '$$typeof': // These names are a little too common. We should probably have a way to // have the Flight runtime extract the inner target instead. return target.$$typeof; case 'filepath': return target.filepath; case 'name': return target.name; // We need to special case this because createElement reads it if we pass this // reference. case 'defaultProps': return undefined; case '__esModule': // Something is conditionally checking which export to use. We'll pretend to be // an ESM compat module but then we'll check again on the client. target.default = { $$typeof: MODULE_REFERENCE, filepath: target.filepath, // This a placeholder value that tells the client to conditionally use the // whole object or just the default export. name: '', }; return true; } let cachedReference = target[name]; if (!cachedReference) { cachedReference = target[name] = { $$typeof: MODULE_REFERENCE, filepath: target.filepath, name: name, }; } return cachedReference; }, set: function () { throw new Error('Cannot assign to a client module from a server module.'); }, }; require.extensions['.client.js'] = function (module, path) { const moduleId = url.pathToFileURL(path).href; const moduleReference: { [string]: any } = { $$typeof: MODULE_REFERENCE, filepath: moduleId, name: '*', // Represents the whole object instead of a particular import. }; module.exports = new Proxy(moduleReference, proxyHandlers); }; const originalResolveFilename = Module._resolveFilename; Module._resolveFilename = function (request, parent, isMain, options) { const resolved = originalResolveFilename.apply(this, arguments); if (resolved.endsWith('.server.js')) { if ( parent && parent.filename && !parent.filename.endsWith('.server.js') ) { let reason; if (request.endsWith('.server.js')) { reason = `"${request}"`; } else { reason = `"${request}" (which expands to "${resolved}")`; } throw new Error( `Cannot import ${reason} from "${parent.filename}". ` + 'By react-server convention, .server.js files can only be imported from other .server.js files. ' + 'That way nobody accidentally sends these to the client by indirectly importing it.', ); } } return resolved; }; }; ================================================ FILE: examples/with-react-server-components/plugin/ReactFlightWebpackPlugin.js ================================================ "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _path = require("path"); var _url = require("url"); var _neoAsync = _interopRequireDefault(require("neo-async")); var _ModuleDependency = _interopRequireDefault(require("webpack/lib/dependencies/ModuleDependency")); var _NullDependency = _interopRequireDefault(require("webpack/lib/dependencies/NullDependency")); var _AsyncDependenciesBlock = _interopRequireDefault(require("webpack/lib/AsyncDependenciesBlock")); var _Template = _interopRequireDefault(require("webpack/lib/Template")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } class ClientReferenceDependency extends _ModuleDependency.default { constructor(request) { super(request); } get type() { return 'client-reference'; } } // This is the module that will be used to anchor all client references to. // I.e. it will have all the client files as async deps from this point on. // We use the Flight client implementation because you can't get to these // without the client runtime so it's the first time in the loading sequence // you might want them. // TODO - fix this; // const clientFileName = require.resolve('../'); const clientFileName = (0, _path.join)(__dirname, '../node_modules/react-server-dom-webpack/index.js'); const PLUGIN_NAME = 'React Server Plugin'; class ReactFlightWebpackPlugin { constructor(options) { _defineProperty(this, "clientReferences", void 0); _defineProperty(this, "chunkName", void 0); _defineProperty(this, "manifestFilename", void 0); if (!options || typeof options.isServer !== 'boolean') { throw new Error(PLUGIN_NAME + ': You must specify the isServer option as a boolean.'); } if (options.isServer) { throw new Error('TODO: Implement the server compiler.'); } if (!options.clientReferences) { this.clientReferences = [{ directory: '.', recursive: true, include: /\.client\.(js|ts|jsx|tsx)$/ }]; } else if (typeof options.clientReferences === 'string' || !Array.isArray(options.clientReferences)) { this.clientReferences = options.clientReferences; } else { this.clientReferences = options.clientReferences; } if (typeof options.chunkName === 'string') { this.chunkName = options.chunkName; if (!/\[(index|request)\]/.test(this.chunkName)) { this.chunkName += '[index]'; } } else { this.chunkName = 'client[index]'; } this.manifestFilename = options.manifestFilename || 'react-client-manifest.json'; } apply(compiler) { let resolvedClientReferences; const run = (params, callback) => { // First we need to find all client files on the file system. We do this early so // that we have them synchronously available later when we need them. This might // not be needed anymore since we no longer need to compile the module itself in // a special way. So it's probably better to do this lazily and in parallel with // other compilation. const contextResolver = compiler.resolverFactory.get('context', {}); this.resolveAllClientFiles(compiler.context, contextResolver, compiler.inputFileSystem, compiler.createContextModuleFactory(), (err, resolvedClientRefs) => { if (err) { callback(err); return; } resolvedClientReferences = resolvedClientRefs; callback(); }); }; compiler.hooks.run.tapAsync(PLUGIN_NAME, run); compiler.hooks.watchRun.tapAsync(PLUGIN_NAME, run); compiler.hooks.compilation.tap(PLUGIN_NAME, (compilation, { normalModuleFactory }) => { compilation.dependencyFactories.set(ClientReferenceDependency, normalModuleFactory); compilation.dependencyTemplates.set(ClientReferenceDependency, new _NullDependency.default.Template()); compilation.hooks.buildModule.tap(PLUGIN_NAME, module => { // We need to add all client references as dependency of something in the graph so // Webpack knows which entries need to know about the relevant chunks and include the // map in their runtime. The things that actually resolves the dependency is the Flight // client runtime. So we add them as a dependency of the Flight client runtime. // Anything that imports the runtime will be made aware of these chunks. // TODO: Warn if we don't find this file anywhere in the compilation. if (module.resource !== clientFileName) { return; } if (resolvedClientReferences) { for (let i = 0; i < resolvedClientReferences.length; i++) { const dep = resolvedClientReferences[i]; const chunkName = this.chunkName.replace(/\[index\]/g, '' + i).replace(/\[request\]/g, _Template.default.toPath(dep.userRequest)); const block = new _AsyncDependenciesBlock.default({ name: chunkName }, module, null, dep.require); block.addDependency(dep); module.addBlock(block); } } }); }); compiler.hooks.emit.tap(PLUGIN_NAME, compilation => { const json = {}; compilation.chunkGroups.forEach(chunkGroup => { const chunkIds = chunkGroup.chunks.map(c => c.id); function recordModule(id, mod) { // TODO: Hook into deps instead of the target module. // That way we know by the type of dep whether to include. // It also resolves conflicts when the same module is in multiple chunks. if (!/\.client\.(js|jsx|ts|tsx)$/.test(mod.resource)) { return; } const moduleExports = {}; ['', '*'].concat(mod.buildMeta.providedExports).forEach(name => { moduleExports[name] = { id: id, chunks: chunkIds, name: name }; }); const href = (0, _url.pathToFileURL)(mod.resource).href; if (href !== undefined) { json[href] = moduleExports; } } chunkGroup.chunks.forEach(chunk => { chunk.getModules().forEach(mod => { recordModule(mod.id, mod); // If this is a concatenation, register each child to the parent ID. if (mod.modules) { mod.modules.forEach(concatenatedMod => { recordModule(mod.id, concatenatedMod); }); } }); }); }); const output = JSON.stringify(json, null, 2); compilation.assets[this.manifestFilename] = { source() { return output; }, size() { return output.length; } }; }); } // This attempts to replicate the dynamic file path resolution used for other wildcard // resolution in Webpack is using. resolveAllClientFiles(context, contextResolver, fs, contextModuleFactory, callback) { _neoAsync.default.map(this.clientReferences, (clientReferencePath, cb) => { if (typeof clientReferencePath === 'string') { cb(null, [new ClientReferenceDependency(clientReferencePath)]); return; } const clientReferenceSearch = clientReferencePath; contextResolver.resolve({}, context, clientReferencePath.directory, {}, (err, resolvedDirectory) => { if (err) return cb(err); const options = { resource: resolvedDirectory, resourceQuery: '', recursive: clientReferenceSearch.recursive === undefined ? true : clientReferenceSearch.recursive, regExp: clientReferenceSearch.include, include: undefined, exclude: clientReferenceSearch.exclude }; contextModuleFactory.resolveDependencies(fs, options, (err2, deps) => { if (err2) return cb(err2); const clientRefDeps = deps.map(dep => { const request = (0, _path.join)(resolvedDirectory, dep.request); const clientRefDep = new ClientReferenceDependency(request); clientRefDep.userRequest = dep.userRequest; return clientRefDep; }); cb(null, clientRefDeps); }); }); }, (err, result) => { if (err) return callback(err); const flat = []; for (let i = 0; i < result.length; i++) { flat.push.apply(flat, result[i]); } callback(null, flat); }); } } exports.default = ReactFlightWebpackPlugin; ================================================ FILE: examples/with-react-server-components/plugin/ReactFlightWebpackPlugin.ts ================================================ /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * * @flow */ import { join } from 'path'; import { pathToFileURL } from 'url'; import asyncLib from 'neo-async'; import ModuleDependency from 'webpack/lib/dependencies/ModuleDependency'; import NullDependency from 'webpack/lib/dependencies/NullDependency'; import AsyncDependenciesBlock from 'webpack/lib/AsyncDependenciesBlock'; import Template from 'webpack/lib/Template'; class ClientReferenceDependency extends ModuleDependency { constructor(request) { super(request); } get type() { return 'client-reference'; } } // This is the module that will be used to anchor all client references to. // I.e. it will have all the client files as async deps from this point on. // We use the Flight client implementation because you can't get to these // without the client runtime so it's the first time in the loading sequence // you might want them. // TODO - fix this; // const clientFileName = require.resolve('../'); const clientFileName = join( __dirname, '../node_modules/react-server-dom-webpack/index.js', ); type ClientReferenceSearchPath = { directory: string; recursive?: boolean; include: RegExp; exclude?: RegExp; }; type ClientReferencePath = string | ClientReferenceSearchPath; type Options = { isServer: boolean; clientReferences?: ClientReferencePath | ReadonlyArray; chunkName?: string; manifestFilename?: string; }; const PLUGIN_NAME = 'React Server Plugin'; export default class ReactFlightWebpackPlugin { clientReferences: ReadonlyArray; chunkName: string; manifestFilename: string; constructor(options: Options) { if (!options || typeof options.isServer !== 'boolean') { throw new Error( PLUGIN_NAME + ': You must specify the isServer option as a boolean.', ); } if (options.isServer) { throw new Error('TODO: Implement the server compiler.'); } if (!options.clientReferences) { this.clientReferences = [ { directory: '.', recursive: true, include: /\.client\.(js|ts|jsx|tsx)$/, }, ]; } else if ( typeof options.clientReferences === 'string' || !Array.isArray(options.clientReferences) ) { this.clientReferences = options.clientReferences; } else { this.clientReferences = options.clientReferences; } if (typeof options.chunkName === 'string') { this.chunkName = options.chunkName; if (!/\[(index|request)\]/.test(this.chunkName)) { this.chunkName += '[index]'; } } else { this.chunkName = 'client[index]'; } this.manifestFilename = options.manifestFilename || 'react-client-manifest.json'; } apply(compiler: any) { let resolvedClientReferences; const run = (params, callback) => { // First we need to find all client files on the file system. We do this early so // that we have them synchronously available later when we need them. This might // not be needed anymore since we no longer need to compile the module itself in // a special way. So it's probably better to do this lazily and in parallel with // other compilation. const contextResolver = compiler.resolverFactory.get('context', {}); this.resolveAllClientFiles( compiler.context, contextResolver, compiler.inputFileSystem, compiler.createContextModuleFactory(), (err, resolvedClientRefs) => { if (err) { callback(err); return; } resolvedClientReferences = resolvedClientRefs; callback(); }, ); }; compiler.hooks.run.tapAsync(PLUGIN_NAME, run); compiler.hooks.watchRun.tapAsync(PLUGIN_NAME, run); compiler.hooks.compilation.tap( PLUGIN_NAME, (compilation, { normalModuleFactory }) => { compilation.dependencyFactories.set( ClientReferenceDependency, normalModuleFactory, ); compilation.dependencyTemplates.set( ClientReferenceDependency, new NullDependency.Template(), ); compilation.hooks.buildModule.tap(PLUGIN_NAME, (module) => { // We need to add all client references as dependency of something in the graph so // Webpack knows which entries need to know about the relevant chunks and include the // map in their runtime. The things that actually resolves the dependency is the Flight // client runtime. So we add them as a dependency of the Flight client runtime. // Anything that imports the runtime will be made aware of these chunks. // TODO: Warn if we don't find this file anywhere in the compilation. if (module.resource !== clientFileName) { return; } if (resolvedClientReferences) { for (let i = 0; i < resolvedClientReferences.length; i++) { const dep = resolvedClientReferences[i]; const chunkName = this.chunkName .replace(/\[index\]/g, '' + i) .replace(/\[request\]/g, Template.toPath(dep.userRequest)); const block = new AsyncDependenciesBlock( { name: chunkName, }, module, null, dep.require, ); block.addDependency(dep); module.addBlock(block); } } }); }, ); compiler.hooks.emit.tap(PLUGIN_NAME, (compilation) => { const json = {}; compilation.chunkGroups.forEach((chunkGroup) => { const chunkIds = chunkGroup.chunks.map((c) => c.id); function recordModule(id, mod) { // TODO: Hook into deps instead of the target module. // That way we know by the type of dep whether to include. // It also resolves conflicts when the same module is in multiple chunks. if (!/\.client\.(js|jsx|ts|tsx)$/.test(mod.resource)) { return; } const moduleExports = {}; ['', '*'].concat(mod.buildMeta.providedExports).forEach((name) => { moduleExports[name] = { id: id, chunks: chunkIds, name: name, }; }); const href = pathToFileURL(mod.resource).href; if (href !== undefined) { json[href] = moduleExports; } } chunkGroup.chunks.forEach((chunk) => { chunk.getModules().forEach((mod) => { recordModule(mod.id, mod); // If this is a concatenation, register each child to the parent ID. if (mod.modules) { mod.modules.forEach((concatenatedMod) => { recordModule(mod.id, concatenatedMod); }); } }); }); }); const output = JSON.stringify(json, null, 2); compilation.assets[this.manifestFilename] = { source() { return output; }, size() { return output.length; }, }; }); } // This attempts to replicate the dynamic file path resolution used for other wildcard // resolution in Webpack is using. resolveAllClientFiles( context: string, contextResolver: any, fs: any, contextModuleFactory: any, callback: ( err: null | Error, result?: ReadonlyArray, ) => void, ) { asyncLib.map( this.clientReferences, ( clientReferencePath: string | ClientReferenceSearchPath, cb: ( err: null | Error, result?: ReadonlyArray, ) => void, ): void => { if (typeof clientReferencePath === 'string') { cb(null, [new ClientReferenceDependency(clientReferencePath)]); return; } const clientReferenceSearch: ClientReferenceSearchPath = clientReferencePath; contextResolver.resolve( {}, context, clientReferencePath.directory, {}, (err, resolvedDirectory) => { if (err) return cb(err); const options = { resource: resolvedDirectory, resourceQuery: '', recursive: clientReferenceSearch.recursive === undefined ? true : clientReferenceSearch.recursive, regExp: clientReferenceSearch.include, include: undefined, exclude: clientReferenceSearch.exclude, }; contextModuleFactory.resolveDependencies( fs, options, (err2: null | Error, deps: Array) => { if (err2) return cb(err2); const clientRefDeps = deps.map((dep) => { const request = join(resolvedDirectory, dep.request); const clientRefDep = new ClientReferenceDependency(request); clientRefDep.userRequest = dep.userRequest; return clientRefDep; }); cb(null, clientRefDeps); }, ); }, ); }, ( err: null | Error, result: ReadonlyArray>, ): void => { if (err) return callback(err); const flat = []; for (let i = 0; i < result.length; i++) { flat.push.apply(flat, result[i]); } callback(null, flat); }, ); } } ================================================ FILE: examples/with-react-server-components/plugin/__tests__/ReactFlightWebpackPlugin.spec.ts ================================================ const path = require('path'); const os = require('os'); function getDependencies(mode) { jest.resetModuleRegistry(); let webpack; if (mode === 'wp5') { webpack = jest.requireActual('webpack5'); // The code we are testing (ReactFlightWebpackPlugin) directly imports `webpack`. It cannot depend upon `webpack5` as // consumers of `ReactFlightWebpackPlugin` are more likely to have installed wp5 just as `webpack`. So we fix this by mocking the // `webpack` module, and return the webpack 5 instance that we required. jest.mock('webpack', () => { return webpack; }); // Sanity-check. If the webpack in package.json changes, this should catch that expect(webpack.version).toMatch(/5\.[0-9]*\.[0-9]*/); } else { webpack = jest.requireActual('webpack'); // Sanity-check. If the webpack in package.json changes, this should catch that expect(webpack.version).toMatch(/4\.[0-9]*\.[0-9]*/); } const FlightPlugin = require('../ReactFlightWebpackPlugin').default; console.log({ FlightPlugin, }); return { FlightPlugin, webpack, }; } // const fixturePath = './packages/react-server-dom-webpack/src/__tests__/fixture'; const fixturePath = './plugin/__tests__/fixture'; describe('ReactFlightWebpackPlugin', () => { // Running webpack can be slow, so we increase Jest's default timeout. These values are // "magic", and not backed by any kind of logic or reasoning. jest.setTimeout(5000 * 5); test('produces manifest - webpack v4', (done) => { const { webpack, FlightPlugin } = getDependencies('wp4'); const entry = path.resolve(path.join(__dirname, 'fixture', 'entry.js')); const plugin = new FlightPlugin({ isServer: false }); const output = webpack({ entry: { main: entry, client: path.resolve(path.join(__dirname, 'fixture', 'Form.client.js')), }, plugins: [plugin], output: { path: path.resolve(path.join(os.tmpdir(), 'output')), }, mode: 'development', }); output.run((err, stats) => { expect(err).toBeNull(); // in webpack 4, we can read the assets of the compilation object. This doesn't work in webpack 5 // as webpack 5 removes the source from the assets object, to prevent memory leaks. const fileName = plugin.manifestFilename; const pluginOutput = stats.compilation.assets[fileName]; const producedManifest = pluginOutput.source(); assert(producedManifest); done(); }); }); test.only('produces manifest - webpack v4 using real code', (done) => { const { webpack, FlightPlugin } = getDependencies('wp4'); const entry = path.resolve( path.join(__dirname, '../../src/', 'index.client.tsx'), ); console.log('entry: ', entry); const plugin = new FlightPlugin({ isServer: false }); const output = webpack({ entry: [entry], plugins: [plugin], output: { path: path.resolve(path.join(os.tmpdir(), 'output')), }, resolve: { extensions: ['.ts', '.tsx', '.js', '.json', '.mjs'], }, mode: 'development', module: { rules: [ { test: /\.(js|jsx|ts|tsx)?$/, // use: 'babel-loader', use: ['babel-loader?cacheDirectory'], exclude: /node_modules/, }, ], }, }); output.run((err, stats) => { expect(err).toBeNull(); // in webpack 4, we can read the assets of the compilation object. This doesn't work in webpack 5 // as webpack 5 removes the source from the assets object, to prevent memory leaks. const fileName = plugin.manifestFilename; const pluginOutput = stats.compilation.assets[fileName]; const producedManifest = pluginOutput.source(); const key = 'file://' + path.resolve(path.join(__dirname, '../../src', 'index.client.tsx')); const manifestObj = JSON.parse(producedManifest); console.log({ key, manifestObj, m: manifestObj[key], }); // file:///Users/sibelius/Dev/entria/feedback/rsc/server-components-boilerplate/src/index.client.tsx // file:///Users/sibelius/Dev/entria/feedback/rsc/server-components-boilerplate/plugin/src/index.client.ts const clientPath = './src'; expect(manifestObj[key]).toStrictEqual( expect.objectContaining({ '': { chunks: ['main'], id: `${clientPath}/index.client.tsx`, name: '', }, '*': { chunks: ['main'], id: `${clientPath}/index.client.tsx`, name: '*', }, }), ); done(); }); }); test.skip('produces manifest - webpack v5', (done) => { const entry = path.resolve(path.join(__dirname, 'fixture', 'entry.js')); const { webpack, FlightPlugin } = getDependencies('wp5'); const plugin = new FlightPlugin({ isServer: false }); const fileName = plugin.manifestFilename; const output = webpack({ entry: { main: entry, client: path.resolve(path.join(__dirname, 'fixture', 'Form.client.js')), }, plugins: [plugin], cache: undefined, output: { // Output path: path.resolve(path.join(os.tmpdir(), 'output+2')), // Make webpack always want to emit files, regardless if they exist or not // This aids in development of the tests, as webpack 5 will not emit fi the file is already existing. compareBeforeEmit: false, }, mode: 'development', }); const originalFileSystem = output.outputFileSystem; output.outputFileSystem = { ...originalFileSystem, writeFile: jest.fn((dest, contents, cb) => { // Call the callback, but don't actually write anything. cb(null); }), }; output.run((err, stats) => { expect(err).toBeNull(); expect(output.outputFileSystem.writeFile).toHaveBeenCalledWith( expect.stringContaining(fileName), expect.anything(), expect.anything(), ); const calls = output.outputFileSystem.writeFile.mock.calls; // Get the idx that was called with the fileName, const idx = calls.findIndex((val) => { return val[0].includes(fileName); }); const contents = output.outputFileSystem.writeFile.mock.calls[ idx ][1].toString(); // Check that the contents match with what we expect assert(contents); done(); }); }); }); function assert(manifestContents) { const key = 'file://' + path.resolve(path.join(__dirname, 'fixture', 'Form.client.js')); const manifestObj = JSON.parse(manifestContents); expect(manifestObj[key]).toStrictEqual( expect.objectContaining({ '': { chunks: ['client'], id: `${fixturePath}/Form.client.js`, name: '', }, '*': { chunks: ['client'], id: `${fixturePath}/Form.client.js`, name: '*', }, Form: { chunks: ['client'], id: `${fixturePath}/Form.client.js`, name: 'Form', }, }), ); } ================================================ FILE: examples/with-react-server-components/plugin/__tests__/fixture/Form.client.js ================================================ export function Form() { console.log('Form Rendered!'); } ================================================ FILE: examples/with-react-server-components/plugin/__tests__/fixture/FormServer.server.js ================================================ export default function Foo() { console.log('Form!'); } ================================================ FILE: examples/with-react-server-components/plugin/__tests__/fixture/entry.js ================================================ const ClientComponent = require('./Form.client').Form; const ServerComponent = require('./FormServer.server.js'); console.log(ClientComponent, ServerComponent); ================================================ FILE: examples/with-react-server-components/plugin/__tests__/fixture/package.json ================================================ { "name": "fixture" } ================================================ FILE: examples/with-react-server-components/public/index.html ================================================ <%= htmlWebpackPlugin.tags.headTags %> React App
<%= htmlWebpackPlugin.tags.bodyTags %> ================================================ FILE: examples/with-react-server-components/public/robots.txt ================================================ User-agent: * ================================================ FILE: examples/with-react-server-components/public/style.css ================================================ /* -------------------------------- CSSRESET --------------------------------*/ /* CSS Reset adapted from https://dev.to/hankchizljaw/a-modern-css-reset-6p3 */ /* Box sizing rules */ *, *::before, *::after { box-sizing: border-box; } /* Remove default padding */ ul[class], ol[class] { padding: 0; } /* Remove default margin */ body, h1, h2, h3, h4, p, ul[class], ol[class], li, figure, figcaption, blockquote, dl, dd { margin: 0; } /* Set core body defaults */ body { min-height: 100vh; scroll-behavior: smooth; text-rendering: optimizeSpeed; line-height: 1.5; } /* Remove list styles on ul, ol elements with a class attribute */ ul[class], ol[class] { list-style: none; } /* A elements that don't have a class get default styles */ a:not([class]) { text-decoration-skip-ink: auto; } /* Make images easier to work with */ img { max-width: 100%; display: block; } /* Natural flow and rhythm in articles by default */ article > * + * { margin-block-start: 1em; } /* Inherit fonts for inputs and buttons */ input, button, textarea, select { font: inherit; } /* Remove all animations and transitions for people that prefer not to see them */ @media (prefers-reduced-motion: reduce) { * { animation-duration: 0.01ms !important; animation-iteration-count: 1 !important; transition-duration: 0.01ms !important; scroll-behavior: auto !important; } } /* -------------------------------- /CSSRESET --------------------------------*/ :root { /* Colors */ --main-border-color: #ddd; --primary-border: #037dba; --gray-20: #404346; --gray-60: #8a8d91; --gray-70: #bcc0c4; --gray-80: #c9ccd1; --gray-90: #e4e6eb; --gray-95: #f0f2f5; --gray-100: #f5f7fa; --primary-blue: #037dba; --secondary-blue: #0396df; --tertiary-blue: #c6efff; --flash-blue: #4cf7ff; --outline-blue: rgba(4, 164, 244, 0.6); --navy-blue: #035e8c; --red-25: #bd0d2a; --secondary-text: #65676b; --white: #fff; --yellow: #fffae1; --outline-box-shadow: 0 0 0 2px var(--outline-blue); --outline-box-shadow-contrast: 0 0 0 2px var(--navy-blue); /* Fonts */ --sans-serif: -apple-system, system-ui, BlinkMacSystemFont, 'Segoe UI', Roboto, Ubuntu, Helvetica, sans-serif; --monospace: Menlo, Consolas, Monaco, Liberation Mono, Lucida Console, monospace; } html { font-size: 100%; } body { font-family: var(--sans-serif); background: var(--gray-100); font-weight: 400; line-height: 1.75; } h1, h2, h3, h4, h5 { margin: 0; font-weight: 700; line-height: 1.3; } h1 { font-size: 3.052rem; } h2 { font-size: 2.441rem; } h3 { font-size: 1.953rem; } h4 { font-size: 1.563rem; } h5 { font-size: 1.25rem; } small, .text_small { font-size: 0.8rem; } pre, code { font-family: var(--monospace); border-radius: 6px; } pre { background: var(--gray-95); padding: 12px; line-height: 1.5; } code { background: var(--yellow); padding: 0 3px; font-size: 0.94rem; word-break: break-word; } pre code { background: none; } a { color: var(--primary-blue); } .text-with-markdown h1, .text-with-markdown h2, .text-with-markdown h3, .text-with-markdown h4, .text-with-markdown h5 { margin-block: 2rem 0.7rem; margin-inline: 0; } .text-with-markdown blockquote { font-style: italic; color: var(--gray-20); border-left: 3px solid var(--gray-80); padding-left: 10px; } hr { border: 0; height: 0; border-top: 1px solid rgba(0, 0, 0, 0.1); border-bottom: 1px solid rgba(255, 255, 255, 0.3); } /* ---------------------------------------------------------------------------*/ .main { display: flex; height: 100vh; width: 100%; overflow: hidden; } .col { height: 100%; } .col:last-child { flex-grow: 1; } .logo { height: 20px; width: 22px; margin-inline-end: 10px; } .edit-button { border-radius: 100px; letter-spacing: 0.12em; text-transform: uppercase; padding: 6px 20px 8px; cursor: pointer; font-weight: 700; outline-style: none; } .edit-button--solid { background: var(--primary-blue); color: var(--white); border: none; margin-inline-start: 6px; transition: all 0.2s ease-in-out; } .edit-button--solid:hover { background: var(--secondary-blue); } .edit-button--solid:focus { box-shadow: var(--outline-box-shadow-contrast); } .edit-button--outline { background: var(--white); color: var(--primary-blue); border: 1px solid var(--primary-blue); margin-inline-start: 12px; transition: all 0.1s ease-in-out; } .edit-button--outline:disabled { opacity: 0.5; } .edit-button--outline:hover:not([disabled]) { background: var(--primary-blue); color: var(--white); } .edit-button--outline:focus { box-shadow: var(--outline-box-shadow); } ul.notes-list { padding: 16px 0; } .notes-list > li { padding: 0 16px; } .notes-empty { padding: 16px; } .sidebar { background: var(--white); box-shadow: 0px 8px 24px rgba(0, 0, 0, 0.1), 0px 2px 2px rgba(0, 0, 0, 0.1); overflow-y: scroll; z-index: 1000; flex-shrink: 0; max-width: 350px; min-width: 250px; width: 30%; } .sidebar-header { letter-spacing: 0.15em; text-transform: uppercase; padding: 36px 16px 16px; display: flex; align-items: center; } .sidebar-menu { padding: 0 16px 16px; display: flex; justify-content: space-between; } .sidebar-menu > .search { position: relative; flex-grow: 1; } .sidebar-note-list-item { position: relative; margin-bottom: 12px; padding: 16px; width: 100%; display: flex; justify-content: space-between; align-items: flex-start; flex-wrap: wrap; max-height: 100px; transition: max-height 250ms ease-out; transform: scale(1); } .sidebar-note-list-item.note-expanded { max-height: 300px; transition: max-height 0.5s ease; } .sidebar-note-list-item.flash { animation-name: flash; animation-duration: 0.6s; } .sidebar-note-open { position: absolute; top: 0; left: 0; right: 0; bottom: 0; width: 100%; z-index: 0; border: none; border-radius: 6px; text-align: start; background: var(--gray-95); cursor: pointer; outline-style: none; color: transparent; font-size: 0px; } .sidebar-note-open:focus { box-shadow: var(--outline-box-shadow); } .sidebar-note-open:hover { background: var(--gray-90); } .sidebar-note-header { z-index: 1; max-width: 85%; pointer-events: none; } .sidebar-note-header > strong { display: block; font-size: 1.25rem; line-height: 1.2; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } .sidebar-note-toggle-expand { z-index: 2; border-radius: 50%; height: 24px; border: 1px solid var(--gray-60); cursor: pointer; flex-shrink: 0; visibility: hidden; opacity: 0; cursor: default; transition: visibility 0s linear 20ms, opacity 300ms; outline-style: none; } .sidebar-note-toggle-expand:focus { box-shadow: var(--outline-box-shadow); } .sidebar-note-open:hover + .sidebar-note-toggle-expand, .sidebar-note-open:focus + .sidebar-note-toggle-expand, .sidebar-note-toggle-expand:hover, .sidebar-note-toggle-expand:focus { visibility: visible; opacity: 1; transition: visibility 0s linear 0s, opacity 300ms; } .sidebar-note-toggle-expand img { width: 10px; height: 10px; } .sidebar-note-excerpt { pointer-events: none; z-index: 2; flex: 1 1 250px; color: var(--secondary-text); position: relative; animation: slideIn 100ms; } .search input { padding: 0 16px; border-radius: 100px; border: 1px solid var(--gray-90); width: 100%; height: 100%; outline-style: none; } .search input:focus { box-shadow: var(--outline-box-shadow); } .search .spinner { position: absolute; right: 10px; top: 10px; } .note-viewer { display: flex; align-items: center; justify-content: center; } .note { background: var(--white); box-shadow: 0px 0px 5px rgba(0, 0, 0, 0.1), 0px 0px 1px rgba(0, 0, 0, 0.1); border-radius: 8px; height: 95%; width: 95%; min-width: 400px; padding: 8%; overflow-y: auto; } .note--empty-state { margin-inline: 20px 20px; } .note-text--empty-state { font-size: 1.5rem; } .note-header { display: flex; justify-content: space-between; align-items: center; flex-wrap: wrap-reverse; margin-inline-start: -12px; } .note-menu { display: flex; justify-content: space-between; align-items: center; flex-grow: 1; } .note-title { line-height: 1.3; flex-grow: 1; overflow-wrap: break-word; margin-inline-start: 12px; } .note-updated-at { color: var(--secondary-text); white-space: nowrap; margin-inline-start: 12px; } .note-preview { margin-block-start: 50px; } .note-editor { background: var(--white); display: flex; height: 100%; width: 100%; padding: 58px; overflow-y: auto; } .note-editor .label { margin-bottom: 20px; } .note-editor-form { display: flex; flex-direction: column; width: 400px; flex-shrink: 0; position: sticky; top: 0; } .note-editor-form input, .note-editor-form textarea { background: none; border: 1px solid var(--gray-70); border-radius: 2px; font-family: var(--monospace); font-size: 0.8rem; padding: 12px; outline-style: none; } .note-editor-form input:focus, .note-editor-form textarea:focus { box-shadow: var(--outline-box-shadow); } .note-editor-form input { height: 44px; margin-bottom: 16px; } .note-editor-form textarea { height: 100%; max-width: 400px; } .note-editor-menu { display: flex; justify-content: flex-end; align-items: center; margin-bottom: 12px; } .note-editor-preview { margin-inline-start: 40px; width: 100%; } .note-editor-done, .note-editor-delete { display: flex; justify-content: space-between; align-items: center; border-radius: 100px; letter-spacing: 0.12em; text-transform: uppercase; padding: 6px 20px 8px; cursor: pointer; font-weight: 700; margin-inline-start: 12px; outline-style: none; transition: all 0.2s ease-in-out; } .note-editor-done:disabled, .note-editor-delete:disabled { opacity: 0.5; } .note-editor-done { border: none; background: var(--primary-blue); color: var(--white); } .note-editor-done:focus { box-shadow: var(--outline-box-shadow-contrast); } .note-editor-done:hover:not([disabled]) { background: var(--secondary-blue); } .note-editor-delete { border: 1px solid var(--red-25); background: var(--white); color: var(--red-25); } .note-editor-delete:focus { box-shadow: var(--outline-box-shadow); } .note-editor-delete:hover:not([disabled]) { background: var(--red-25); color: var(--white); } /* Hack to color our svg */ .note-editor-delete:hover:not([disabled]) img { filter: grayscale(1) invert(1) brightness(2); } .note-editor-done > img { width: 14px; } .note-editor-delete > img { width: 10px; } .note-editor-done > img, .note-editor-delete > img { margin-inline-end: 12px; } .note-editor-done[disabled], .note-editor-delete[disabled] { opacity: 0.5; } .label { display: inline-block; border-radius: 100px; letter-spacing: 0.05em; text-transform: uppercase; font-weight: 700; padding: 4px 14px; } .label--preview { background: rgba(38, 183, 255, 0.15); color: var(--primary-blue); } .text-with-markdown p { margin-bottom: 16px; } .text-with-markdown img { width: 100%; } /* https://codepen.io/mandelid/pen/vwKoe */ .spinner { display: inline-block; transition: opacity linear 0.1s; width: 20px; height: 20px; border: 3px solid rgba(80, 80, 80, 0.5); border-radius: 50%; border-top-color: #fff; animation: spin 1s ease-in-out infinite; opacity: 0; } .spinner--active { opacity: 1; } .skeleton::after { content: 'Loading...'; } .skeleton { height: 100%; background-color: #eee; background-image: linear-gradient(90deg, #eee, #f5f5f5, #eee); background-size: 200px 100%; background-repeat: no-repeat; border-radius: 4px; display: block; line-height: 1; width: 100%; animation: shimmer 1.2s ease-in-out infinite; color: transparent; } .skeleton:first-of-type { margin: 0; } .skeleton--button { border-radius: 100px; padding: 6px 20px 8px; width: auto; } .v-stack + .v-stack { margin-block-start: 0.8em; } .offscreen { border: 0; clip: rect(0, 0, 0, 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; width: 1px; position: absolute; } /* ---------------------------------------------------------------------------*/ @keyframes spin { to { transform: rotate(360deg); } } @keyframes spin { to { transform: rotate(360deg); } } @keyframes shimmer { 0% { background-position: -200px 0; } 100% { background-position: calc(200px + 100%) 0; } } @keyframes slideIn { 0% { top: -10px; opacity: 0; } 100% { top: 0; opacity: 1; } } @keyframes flash { 0% { transform: scale(1); opacity: 1; } 50% { transform: scale(1.05); opacity: 0.9; } 100% { transform: scale(1); opacity: 1; } } ================================================ FILE: examples/with-react-server-components/razzle.config.js ================================================ 'use strict'; const path = require('path'); const { StatsWriterPlugin } = require("webpack-stats-plugin") const ReactServerWebpackPlugin = require('./plugin/ReactFlightWebpackPlugin') .default; module.exports = { options: { verbose: true, enableBabelCache: false, }, modifyPaths(opts) { const paths = opts.paths; paths.appServerIndexJs = path.join(paths.appPath, 'src/cli.server'); paths.appClientIndexJs = path.join(paths.appPath, 'src/index.client'); return paths; }, modifyWebpackOptions(opts) { const options = opts.options.webpackOptions; // Enable HtmlWebpackPlugin in iso app if (opts.env.target === 'web') { options.enableHtmlWebpackPlugin = true; } if (opts.env.target === 'node' && opts.env.dev) { options.startServerOptions.nodeArgs.push('--conditions=react-server'); } if (opts.env.target === 'node') { options.jsOutputFilename = `[name].server.js`; options.jsOutputChunkFilename = `[name].chunk.server.js`; } return options; }, modifyWebpackConfig(opts) { const config = opts.webpackConfig; const options = opts.options.webpackOptions; config.output.futureEmitAssets = true; // Enable StatsWriterPlugin if (opts.env.target === 'web') { config.plugins = config.plugins.concat([ new ReactServerWebpackPlugin({isServer: false}) ]); } if (opts.env.target === 'node') { config.module.rules.unshift({ ...options.babelRule, test: /\.client.(js|jsx|ts|tsx)?$/, use: [...[ { loader: require.resolve('./plugin/ReactFlightWebpackLoader'), }],...options.babelRule.use] }) } if (opts.env.target === 'web' && opts.env.dev) { config.devServer.writeToDisk = true; } if (!opts.env.dev) { config.optimization = {...config.optimization, ...{minimize: false}}; } return config; }, } ================================================ FILE: examples/with-react-server-components/sandbox.config.json ================================================ { "container": { "port": 3000 } } ================================================ FILE: examples/with-react-server-components/scripts/seed.js ================================================ /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ 'use strict'; const fs = require('fs'); const path = require('path'); const {readdir, unlink, writeFile} = require('fs/promises'); const startOfYear = require('date-fns/startOfYear'); const sqlite = require('better-sqlite3'); const NOTES_PATH = './notes'; const db = sqlite(path.join(process.cwd(), 'db.sqlite3')) const now = new Date(); const startOfThisYear = startOfYear(now); // Thanks, https://stackoverflow.com/a/9035732 function randomDateBetween(start, end) { return new Date( start.getTime() + Math.random() * (end.getTime() - start.getTime()) ); } const dropTableStatement = 'DROP TABLE IF EXISTS notes;'; const createTableStatement = `CREATE TABLE notes ( id INTEGER PRIMARY KEY AUTOINCREMENT, created_at TIMESTAMP NOT NULL, updated_at TIMESTAMP NOT NULL, title TEXT, body TEXT );`; const insertNoteStatement = `INSERT INTO notes(title, body, created_at, updated_at) VALUES (?, ?, ?, ?)`; const selectTable = 'SELECT * FROM notes'; const seedData = [ [ 'Meeting Notes', 'This is an example note. It contains **Markdown**!', randomDateBetween(startOfThisYear, now).toISOString().split('T')[0], randomDateBetween(startOfThisYear, now).toISOString().split('T')[0], ], [ 'Make a thing', `It's very easy to make some words **bold** and other words *italic* with Markdown. You can even [link to React's website!](https://www.reactjs.org).`, randomDateBetween(startOfThisYear, now).toISOString().split('T')[0], randomDateBetween(startOfThisYear, now).toISOString().split('T')[0], ], [ 'A note with a very long title because sometimes you need more words', `You can write all kinds of [amazing](https://en.wikipedia.org/wiki/The_Amazing) notes in this app! These note live on the server in the \`notes\` folder. ![This app is powered by React](https://upload.wikimedia.org/wikipedia/commons/thumb/1/18/React_Native_Logo.png/800px-React_Native_Logo.png)`, randomDateBetween(startOfThisYear, now).toISOString().split('T')[0], randomDateBetween(startOfThisYear, now).toISOString().split('T')[0], ], ['I wrote this note today', 'It was an excellent note.', now.toISOString().split('T')[0], now.toISOString().split('T')[0]], ]; async function seed() { db.exec(dropTableStatement); db.exec(createTableStatement); seedData.map((row) => db.prepare(insertNoteStatement).run(row)) const res = db.prepare(selectTable).all(); console.log(res) const oldNotes = await readdir(path.resolve(NOTES_PATH)); await Promise.all( oldNotes .filter((filename) => filename.endsWith('.md')) .map((filename) => unlink(path.resolve(NOTES_PATH, filename))) ); await Promise.all( res.map((row) => { const id = row.id; const content = row.body; const data = new Uint8Array(Buffer.from(content)); return writeFile(path.resolve(NOTES_PATH, `${id}.md`), data, (err) => { if (err) { throw err; } }); }) ); } seed(); ================================================ FILE: examples/with-react-server-components/src/App.server.tsx ================================================ import { Suspense } from 'react'; import Note from './Note.server'; import NoteList from './NoteList.server'; import EditButton from './EditButton.client'; import SearchField from './SearchField.client'; import NoteSkeleton from './NoteSkeleton'; import NoteListSkeleton from './NoteListSkeleton'; export default function App({ selectedId, isEditing, searchText }) { return (
React Notes
New
}>
); } ================================================ FILE: examples/with-react-server-components/src/Cache.client.tsx ================================================ import { unstable_getCacheForType, unstable_useCacheRefresh } from 'react'; import { createFromFetch } from 'react-server-dom-webpack'; function createResponseCache() { return new Map(); } export function useRefresh() { const refreshCache = unstable_useCacheRefresh(); return function refresh(key, seededResponse) { refreshCache(createResponseCache, new Map([[key, seededResponse]])); }; } export function useServerResponse(location) { const key = JSON.stringify(location); const cache = unstable_getCacheForType(createResponseCache); let response = cache.get(key); if (response) { return response; } response = createFromFetch( fetch('/react?location=' + encodeURIComponent(key)), ); cache.set(key, response); return response; } ================================================ FILE: examples/with-react-server-components/src/EditButton.client.tsx ================================================ import { unstable_useTransition } from 'react'; import { useLocation } from './LocationContext.client'; export default function EditButton({ noteId, children }) { const [, setLocation] = useLocation(); const [startTransition, isPending] = unstable_useTransition(); const isDraft = noteId == null; return ( ); } ================================================ FILE: examples/with-react-server-components/src/LocationContext.client.tsx ================================================ import { createContext, useContext } from 'react'; console.log({ createContext, useContext, }); export const LocationContext = createContext(); export function useLocation() { return useContext(LocationContext); } ================================================ FILE: examples/with-react-server-components/src/Note.server.tsx ================================================ /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ import { fetch } from 'react-fetch'; import { readFile } from 'react-fs'; import { format } from 'date-fns'; import path from 'path'; import { db } from './db.server'; import NotePreview from './NotePreview'; import EditButton from './EditButton.client'; import NoteEditor from './NoteEditor.client'; export default function Note({ selectedId, isEditing }) { const note = selectedId != null ? fetch(`http://localhost:3000/notes/${selectedId}`).json() : null; if (note === null) { if (isEditing) { return ( ); } else { return (
Click a note on the left to view something! 🥺
); } } let { id, title, body, updated_at } = note; const updatedAt = new Date(updated_at); // We could also read from a file instead. // body = readFile(path.resolve(`./notes/${note.id}.md`), 'utf8'); // Now let's see how the Suspense boundary above lets us not block on this. // fetch('http://localhost:4000/sleep/3000'); if (isEditing) { return ; } else { return (

{title}

Last updated on {format(updatedAt, "d MMM yyyy 'at' h:mm bb")} Edit
); } } ================================================ FILE: examples/with-react-server-components/src/NoteEditor.client.tsx ================================================ /** * Copyright (c) Facebook, Inc. and its affiliates. * * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. * */ import { useState, unstable_useTransition } from 'react'; import { createFromReadableStream } from 'react-server-dom-webpack'; import NotePreview from './NotePreview'; import { useRefresh } from './Cache.client'; import { useLocation } from './LocationContext.client'; export default function NoteEditor({ noteId, initialTitle, initialBody }) { const refresh = useRefresh(); const [title, setTitle] = useState(initialTitle); const [body, setBody] = useState(initialBody); const [location, setLocation] = useLocation(); const [startNavigating, isNavigating] = unstable_useTransition(); const [isSaving, saveNote] = useMutation({ endpoint: noteId !== null ? `/notes/${noteId}` : `/notes`, method: noteId !== null ? 'PUT' : 'POST', }); const [isDeleting, deleteNote] = useMutation({ endpoint: `/notes/${noteId}`, method: 'DELETE', }); async function handleSave() { const payload = { title, body }; const requestedLocation = { selectedId: noteId, isEditing: false, searchText: location.searchText, }; const response = await saveNote(payload, requestedLocation); navigate(response); } async function handleDelete() { const payload = {}; const requestedLocation = { selectedId: null, isEditing: false, searchText: location.searchText, }; const response = await deleteNote(payload, requestedLocation); navigate(response); } function navigate(response) { const cacheKey = response.headers.get('X-Location'); const nextLocation = JSON.parse(cacheKey); const seededResponse = createFromReadableStream(response.body); startNavigating(() => { refresh(cacheKey, seededResponse); setLocation(nextLocation); }); } const isDraft = noteId === null; return (
e.preventDefault()} > { setTitle(e.target.value); }} />