├── .commitlintrc.json ├── .github ├── FUNDING.yml └── workflows │ ├── check-patchable.yml │ ├── release.yml │ └── test.yml ├── .gitignore ├── .husky ├── commit-msg ├── pre-commit └── pre-push ├── .releaserc.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── cron ├── .gitignore ├── app.jsx ├── index.js ├── inject.js ├── package.json └── yarn.lock ├── examples ├── chakra-ui-cloudflare │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── context.tsx │ │ ├── createEmotionCache.ts │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ └── routes │ │ │ └── index.tsx │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── server.js │ ├── tsconfig.json │ └── wrangler.toml ├── emotion-cloudflare │ ├── .eslintrc.js │ ├── .gitignore │ ├── README.md │ ├── app │ │ ├── entry.client.tsx │ │ ├── entry.server.tsx │ │ ├── root.tsx │ │ ├── routes │ │ │ ├── index.tsx │ │ │ ├── jokes-error.tsx │ │ │ ├── jokes.tsx │ │ │ └── use-css-props.tsx │ │ └── styles │ │ │ ├── client.context.tsx │ │ │ ├── createEmotionCache.ts │ │ │ └── server.context.tsx │ ├── package-lock.json │ ├── package.json │ ├── public │ │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── server.js │ ├── tsconfig.json │ └── wrangler.toml └── styled-components │ ├── .eslintrc │ ├── .gitignore │ ├── README.md │ ├── app │ ├── entry.client.tsx │ ├── entry.server.tsx │ ├── root.tsx │ └── routes │ │ └── index.tsx │ ├── package-lock.json │ ├── package.json │ ├── public │ └── favicon.ico │ ├── remix.config.js │ ├── remix.env.d.ts │ ├── styled-components-esbuild-plugin.js │ └── tsconfig.json ├── package.json ├── src ├── __tests__ │ ├── __snapshots__ │ │ └── patching.test.ts.snap │ ├── index.test.ts │ └── patching.test.ts ├── bin │ └── esbuild-override.ts ├── constants.ts ├── index.ts ├── patching.ts └── utils.ts ├── tsconfig.json ├── vite.config.ts └── yarn.lock /.commitlintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "@commitlint/config-conventional" 4 | ] 5 | } -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: aiji42 # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 4 | patreon: # Replace with a single Patreon username 5 | open_collective: # Replace with a single Open Collective username 6 | ko_fi: # Replace with a single Ko-fi username 7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel 8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry 9 | liberapay: # Replace with a single Liberapay username 10 | issuehunt: # Replace with a single IssueHunt username 11 | otechie: # Replace with a single Otechie username 12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry 13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] 14 | -------------------------------------------------------------------------------- /.github/workflows/check-patchable.yml: -------------------------------------------------------------------------------- 1 | name: check-patchable 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | schedule: 11 | - cron: '0 10 * * *' 12 | 13 | jobs: 14 | test: 15 | name: Test 16 | runs-on: ubuntu-latest 17 | steps: 18 | - name: Checkout Repository 19 | uses: actions/checkout@master 20 | - name: Install Dependencies 21 | working-directory: ./cron 22 | run: | 23 | yarn install --no-lockfile 24 | yarn list esbuild remix-esbuild-override 25 | - name: Run Test 26 | working-directory: ./cron 27 | run: yarn test -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | on: 3 | push: 4 | branches: 5 | - main 6 | - beta 7 | jobs: 8 | release: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Checkout this repository 12 | uses: actions/checkout@master 13 | - name: Setup node 14 | uses: actions/setup-node@v3 15 | with: 16 | node-version: '16' 17 | - name: Install dependencies 18 | run: yarn --frozen-lockfile 19 | - name: Build 20 | run: yarn build 21 | - name: Release 22 | env: 23 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 24 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 25 | run: yarn semantic-release -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | push: 4 | branches: 5 | - main 6 | pull_request: 7 | branches: 8 | - main 9 | jobs: 10 | test: 11 | name: Test 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout Repository 15 | uses: actions/checkout@master 16 | - name: Install Dependencies 17 | run: yarn 18 | - name: Run Test 19 | run: yarn test:coverage 20 | - name: Upload Coverage 21 | uses: codecov/codecov-action@v1 22 | with: 23 | token: ${{ secrets.CODECOV_TOKEN }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | node_modules/ 3 | *.log 4 | dist 5 | coverage -------------------------------------------------------------------------------- /.husky/commit-msg: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | yarn commitlint --edit 5 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npx lint-staged 5 | -------------------------------------------------------------------------------- /.husky/pre-push: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | npm run test:run -------------------------------------------------------------------------------- /.releaserc.json: -------------------------------------------------------------------------------- 1 | { 2 | "branches": ["main", {"name": "beta", "prerelease": true}] 3 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributions 2 | 3 | :crystal_ball: Thanks for considering contributing to this project! :crystal_ball: 4 | 5 | These guidelines will help you send a pull request. 6 | 7 | If you're submitting an issue instead, please skip this document. 8 | 9 | If your pull request is related to a typo or the documentation being unclear, please click on the relevant page's `Edit` 10 | button (pencil icon) and directly suggest a correction instead. 11 | 12 | This project was made with your goodwill. The simplest way to give back is by starring and sharing it online. 13 | 14 | Everyone is welcome regardless of personal background. 15 | 16 | ## Development process 17 | 18 | First fork and clone the repository. 19 | 20 | Run: 21 | 22 | ```bash 23 | yarn 24 | ``` 25 | 26 | Make sure everything is correctly setup with: 27 | 28 | ```bash 29 | yarn test:run 30 | ``` 31 | 32 | ## How to write commit messages 33 | 34 | We use [Conventional Commit messages](https://www.conventionalcommits.org/) to automate version management. 35 | 36 | Most common commit message prefixes are: 37 | 38 | * `fix:` which represents bug fixes, and generate a patch release. 39 | * `feat:` which represents a new feature, and generate a minor release. 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 AijiUejima 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![npm version](https://badge.fury.io/js/remix-esbuild-override.svg)](https://badge.fury.io/js/remix-esbuild-override) 2 | [![codecov](https://codecov.io/gh/aiji42/remix-esbuild-override/branch/main/graph/badge.svg?token=3CKLRN020Q)](https://codecov.io/gh/aiji42/remix-esbuild-override) 3 | 4 | # :minidisc: remix-esbuild-override 5 | 6 | :warning: While I believe you will most likely get a lot of benefit from using this library, it can sometimes destroy your product. 7 | Please be sure to verify it and make sure it is safe before releasing it to production. 8 | 9 | ## What is this? 10 | 11 | This is a library that makes it possible to change the configuration values of the [Remix](https://remix.run/) compiler (esbuild). 12 | 13 | For example, Next.js allows you to control webpack option values from a configuration file (`next.config.js`). 14 | Remix does not have that functionality. A member of the development team says in a [PR comment](https://github.com/remix-run/remix/pull/2168#issuecomment-1058193715) that this is because exposing the configuration values would lock in the compiler's choices and also risk breaking the application. 15 | I support that argument, but in actual use cases, I often want to change the settings. 16 | So I decided to provide that functionality outside of Remix (in this 3rd-party library). 17 | 18 | ## Install 19 | 20 | ```bash 21 | # npm 22 | npm install -D remix-esbuild-override 23 | 24 | # yarn 25 | yarn add -D remix-esbuild-override 26 | ``` 27 | 28 | 2. Add `remix-esbuild-override` to `scripts.postinstall` in package.json. 29 | 30 | ```json 31 | "scripts": { 32 | "postinstall": "remix-esbuild-override" 33 | } 34 | ``` 35 | 36 | 3. Run `npm install` or `yarn install` again to run `postinstall` 37 | 38 | ## How to use 39 | 40 | You can define function properties in `remix.config.js` that can override esbuild configuration values. 41 | 42 | ```js 43 | // remix.config.js 44 | const { withEsbuildOverride } = require("remix-esbuild-override"); 45 | 46 | /** 47 | * Define callbacks for the arguments of withEsbuildOverride. 48 | * @param option - Default configuration values defined by the remix compiler 49 | * @param isServer - True for server compilation, false for browser compilation 50 | * @param isDev - True during development. 51 | * @return {EsbuildOption} - You must return the updated option 52 | */ 53 | withEsbuildOverride((option, { isServer, isDev }) => { 54 | // update the option 55 | option.plugins = [someEsbuildPlugin, ...option.plugins]; 56 | 57 | return option; 58 | }); 59 | 60 | /** 61 | * @type {import('@remix-run/dev').AppConfig} 62 | */ 63 | module.exports = { 64 | // ... 65 | }; 66 | ``` 67 | 68 | :memo: NOTE: Compilation is executed twice, once for the server and once for the browser. 69 | 70 | ### Examples 71 | 72 | - [emotion on Cloudflare](https://github.com/aiji42/remix-esbuild-override/tree/main/examples/emotion-cloudflare) 73 | - [Chakra UI on Cloudflare](https://github.com/aiji42/remix-esbuild-override/tree/main/examples/chakra-ui-cloudflare) 74 | - [Styled componets](https://github.com/aiji42/remix-esbuild-override/tree/main/examples/styled-components) 75 | 76 | If you have other example requests, please create an issue. Additional pull requests for examples are also welcome. 77 | 78 | ## Contributing 79 | 80 | Please read [CONTRIBUTING.md](https://github.com/aiji42/remix-esbuild-override/blob/main/CONTRIBUTING.md) for details on our code of conduct, and the process for submitting pull requests to us. 81 | 82 | ## License 83 | 84 | This project is licensed under the MIT License - see the [LICENSE](https://github.com/aiji42/remix-esbuild-override/blob/main/LICENSE) file for details 85 | -------------------------------------------------------------------------------- /cron/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out.js -------------------------------------------------------------------------------- /cron/app.jsx: -------------------------------------------------------------------------------- 1 | import { renderToString } from "react-dom/server"; 2 | 3 | const Greet = () =>

Hello, world!

; 4 | console.log(renderToString()); 5 | -------------------------------------------------------------------------------- /cron/index.js: -------------------------------------------------------------------------------- 1 | const { withEsbuildOverride } = require("remix-esbuild-override"); 2 | const path = require("path"); 3 | 4 | withEsbuildOverride((option) => { 5 | option.inject = [path.resolve(__dirname, "inject.js")]; 6 | return option; 7 | }); 8 | 9 | const main = async () => { 10 | await require("esbuild").build({ 11 | entryPoints: ["app.jsx"], 12 | bundle: true, 13 | minify: true, 14 | outfile: "out.js", 15 | }); 16 | 17 | const res = await require("esbuild").context({ 18 | entryPoints: ["app.jsx"], 19 | bundle: true, 20 | minify: true, 21 | outfile: "out.js", 22 | }); 23 | await res.dispose(); 24 | }; 25 | 26 | main().catch(() => process.exit(1)); 27 | -------------------------------------------------------------------------------- /cron/inject.js: -------------------------------------------------------------------------------- 1 | import * as React from "react"; 2 | export { React }; 3 | -------------------------------------------------------------------------------- /cron/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cron", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "scripts": { 7 | "postinstall": "remix-esbuild-override", 8 | "test": "node index.js && node out.js" 9 | }, 10 | "dependencies": { 11 | "esbuild": "latest", 12 | "react": "^18.0.0", 13 | "react-dom": "^18.0.0", 14 | "remix-esbuild-override": "latest" 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /cron/yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@esbuild/android-arm64@0.17.18": 6 | version "0.17.18" 7 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.17.18.tgz#4aa8d8afcffb4458736ca9b32baa97d7cb5861ea" 8 | integrity sha512-/iq0aK0eeHgSC3z55ucMAHO05OIqmQehiGay8eP5l/5l+iEr4EIbh4/MI8xD9qRFjqzgkc0JkX0LculNC9mXBw== 9 | 10 | "@esbuild/android-arm@0.17.18": 11 | version "0.17.18" 12 | resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.17.18.tgz#74a7e95af4ee212ebc9db9baa87c06a594f2a427" 13 | integrity sha512-EmwL+vUBZJ7mhFCs5lA4ZimpUH3WMAoqvOIYhVQwdIgSpHC8ImHdsRyhHAVxpDYUSm0lWvd63z0XH1IlImS2Qw== 14 | 15 | "@esbuild/android-x64@0.17.18": 16 | version "0.17.18" 17 | resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.17.18.tgz#1dcd13f201997c9fe0b204189d3a0da4eb4eb9b6" 18 | integrity sha512-x+0efYNBF3NPW2Xc5bFOSFW7tTXdAcpfEg2nXmxegm4mJuVeS+i109m/7HMiOQ6M12aVGGFlqJX3RhNdYM2lWg== 19 | 20 | "@esbuild/darwin-arm64@0.17.18": 21 | version "0.17.18" 22 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.17.18.tgz#444f3b961d4da7a89eb9bd35cfa4415141537c2a" 23 | integrity sha512-6tY+djEAdF48M1ONWnQb1C+6LiXrKjmqjzPNPWXhu/GzOHTHX2nh8Mo2ZAmBFg0kIodHhciEgUBtcYCAIjGbjQ== 24 | 25 | "@esbuild/darwin-x64@0.17.18": 26 | version "0.17.18" 27 | resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.17.18.tgz#a6da308d0ac8a498c54d62e0b2bfb7119b22d315" 28 | integrity sha512-Qq84ykvLvya3dO49wVC9FFCNUfSrQJLbxhoQk/TE1r6MjHo3sFF2tlJCwMjhkBVq3/ahUisj7+EpRSz0/+8+9A== 29 | 30 | "@esbuild/freebsd-arm64@0.17.18": 31 | version "0.17.18" 32 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.17.18.tgz#b83122bb468889399d0d63475d5aea8d6829c2c2" 33 | integrity sha512-fw/ZfxfAzuHfaQeMDhbzxp9mc+mHn1Y94VDHFHjGvt2Uxl10mT4CDavHm+/L9KG441t1QdABqkVYwakMUeyLRA== 34 | 35 | "@esbuild/freebsd-x64@0.17.18": 36 | version "0.17.18" 37 | resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.17.18.tgz#af59e0e03fcf7f221b34d4c5ab14094862c9c864" 38 | integrity sha512-FQFbRtTaEi8ZBi/A6kxOC0V0E9B/97vPdYjY9NdawyLd4Qk5VD5g2pbWN2VR1c0xhzcJm74HWpObPszWC+qTew== 39 | 40 | "@esbuild/linux-arm64@0.17.18": 41 | version "0.17.18" 42 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.17.18.tgz#8551d72ba540c5bce4bab274a81c14ed01eafdcf" 43 | integrity sha512-R7pZvQZFOY2sxUG8P6A21eq6q+eBv7JPQYIybHVf1XkQYC+lT7nDBdC7wWKTrbvMXKRaGudp/dzZCwL/863mZQ== 44 | 45 | "@esbuild/linux-arm@0.17.18": 46 | version "0.17.18" 47 | resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.17.18.tgz#e09e76e526df4f665d4d2720d28ff87d15cdf639" 48 | integrity sha512-jW+UCM40LzHcouIaqv3e/oRs0JM76JfhHjCavPxMUti7VAPh8CaGSlS7cmyrdpzSk7A+8f0hiedHqr/LMnfijg== 49 | 50 | "@esbuild/linux-ia32@0.17.18": 51 | version "0.17.18" 52 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.17.18.tgz#47878860ce4fe73a36fd8627f5647bcbbef38ba4" 53 | integrity sha512-ygIMc3I7wxgXIxk6j3V00VlABIjq260i967Cp9BNAk5pOOpIXmd1RFQJQX9Io7KRsthDrQYrtcx7QCof4o3ZoQ== 54 | 55 | "@esbuild/linux-loong64@0.17.18": 56 | version "0.17.18" 57 | resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.17.18.tgz#3f8fbf5267556fc387d20b2e708ce115de5c967a" 58 | integrity sha512-bvPG+MyFs5ZlwYclCG1D744oHk1Pv7j8psF5TfYx7otCVmcJsEXgFEhQkbhNW8otDHL1a2KDINW20cfCgnzgMQ== 59 | 60 | "@esbuild/linux-mips64el@0.17.18": 61 | version "0.17.18" 62 | resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.17.18.tgz#9d896d8f3c75f6c226cbeb840127462e37738226" 63 | integrity sha512-oVqckATOAGuiUOa6wr8TXaVPSa+6IwVJrGidmNZS1cZVx0HqkTMkqFGD2HIx9H1RvOwFeWYdaYbdY6B89KUMxA== 64 | 65 | "@esbuild/linux-ppc64@0.17.18": 66 | version "0.17.18" 67 | resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.17.18.tgz#3d9deb60b2d32c9985bdc3e3be090d30b7472783" 68 | integrity sha512-3dLlQO+b/LnQNxgH4l9rqa2/IwRJVN9u/bK63FhOPB4xqiRqlQAU0qDU3JJuf0BmaH0yytTBdoSBHrb2jqc5qQ== 69 | 70 | "@esbuild/linux-riscv64@0.17.18": 71 | version "0.17.18" 72 | resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.17.18.tgz#8a943cf13fd24ff7ed58aefb940ef178f93386bc" 73 | integrity sha512-/x7leOyDPjZV3TcsdfrSI107zItVnsX1q2nho7hbbQoKnmoeUWjs+08rKKt4AUXju7+3aRZSsKrJtaRmsdL1xA== 74 | 75 | "@esbuild/linux-s390x@0.17.18": 76 | version "0.17.18" 77 | resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.17.18.tgz#66cb01f4a06423e5496facabdce4f7cae7cb80e5" 78 | integrity sha512-cX0I8Q9xQkL/6F5zWdYmVf5JSQt+ZfZD2bJudZrWD+4mnUvoZ3TDDXtDX2mUaq6upMFv9FlfIh4Gfun0tbGzuw== 79 | 80 | "@esbuild/linux-x64@0.17.18": 81 | version "0.17.18" 82 | resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.17.18.tgz#23c26050c6c5d1359c7b774823adc32b3883b6c9" 83 | integrity sha512-66RmRsPlYy4jFl0vG80GcNRdirx4nVWAzJmXkevgphP1qf4dsLQCpSKGM3DUQCojwU1hnepI63gNZdrr02wHUA== 84 | 85 | "@esbuild/netbsd-x64@0.17.18": 86 | version "0.17.18" 87 | resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.17.18.tgz#789a203d3115a52633ff6504f8cbf757f15e703b" 88 | integrity sha512-95IRY7mI2yrkLlTLb1gpDxdC5WLC5mZDi+kA9dmM5XAGxCME0F8i4bYH4jZreaJ6lIZ0B8hTrweqG1fUyW7jbg== 89 | 90 | "@esbuild/openbsd-x64@0.17.18": 91 | version "0.17.18" 92 | resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.17.18.tgz#d7b998a30878f8da40617a10af423f56f12a5e90" 93 | integrity sha512-WevVOgcng+8hSZ4Q3BKL3n1xTv5H6Nb53cBrtzzEjDbbnOmucEVcZeGCsCOi9bAOcDYEeBZbD2SJNBxlfP3qiA== 94 | 95 | "@esbuild/sunos-x64@0.17.18": 96 | version "0.17.18" 97 | resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.17.18.tgz#ecad0736aa7dae07901ba273db9ef3d3e93df31f" 98 | integrity sha512-Rzf4QfQagnwhQXVBS3BYUlxmEbcV7MY+BH5vfDZekU5eYpcffHSyjU8T0xucKVuOcdCsMo+Ur5wmgQJH2GfNrg== 99 | 100 | "@esbuild/win32-arm64@0.17.18": 101 | version "0.17.18" 102 | resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.17.18.tgz#58dfc177da30acf956252d7c8ae9e54e424887c4" 103 | integrity sha512-Kb3Ko/KKaWhjeAm2YoT/cNZaHaD1Yk/pa3FTsmqo9uFh1D1Rfco7BBLIPdDOozrObj2sahslFuAQGvWbgWldAg== 104 | 105 | "@esbuild/win32-ia32@0.17.18": 106 | version "0.17.18" 107 | resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.17.18.tgz#340f6163172b5272b5ae60ec12c312485f69232b" 108 | integrity sha512-0/xUMIdkVHwkvxfbd5+lfG7mHOf2FRrxNbPiKWg9C4fFrB8H0guClmaM3BFiRUYrznVoyxTIyC/Ou2B7QQSwmw== 109 | 110 | "@esbuild/win32-x64@0.17.18": 111 | version "0.17.18" 112 | resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.17.18.tgz#3a8e57153905308db357fd02f57c180ee3a0a1fa" 113 | integrity sha512-qU25Ma1I3NqTSHJUOKi9sAH1/Mzuvlke0ioMJRthLXKm7JiSKVwFghlGbDLOO2sARECGhja4xYfRAZNPAkooYg== 114 | 115 | esbuild@0.17.18: 116 | version "0.17.18" 117 | resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.17.18.tgz#f4f8eb6d77384d68cd71c53eb6601c7efe05e746" 118 | integrity sha512-z1lix43jBs6UKjcZVKOw2xx69ffE2aG0PygLL5qJ9OS/gy0Ewd1gW/PUQIOIQGXBHWNywSc0floSKoMFF8aK2w== 119 | optionalDependencies: 120 | "@esbuild/android-arm" "0.17.18" 121 | "@esbuild/android-arm64" "0.17.18" 122 | "@esbuild/android-x64" "0.17.18" 123 | "@esbuild/darwin-arm64" "0.17.18" 124 | "@esbuild/darwin-x64" "0.17.18" 125 | "@esbuild/freebsd-arm64" "0.17.18" 126 | "@esbuild/freebsd-x64" "0.17.18" 127 | "@esbuild/linux-arm" "0.17.18" 128 | "@esbuild/linux-arm64" "0.17.18" 129 | "@esbuild/linux-ia32" "0.17.18" 130 | "@esbuild/linux-loong64" "0.17.18" 131 | "@esbuild/linux-mips64el" "0.17.18" 132 | "@esbuild/linux-ppc64" "0.17.18" 133 | "@esbuild/linux-riscv64" "0.17.18" 134 | "@esbuild/linux-s390x" "0.17.18" 135 | "@esbuild/linux-x64" "0.17.18" 136 | "@esbuild/netbsd-x64" "0.17.18" 137 | "@esbuild/openbsd-x64" "0.17.18" 138 | "@esbuild/sunos-x64" "0.17.18" 139 | "@esbuild/win32-arm64" "0.17.18" 140 | "@esbuild/win32-ia32" "0.17.18" 141 | "@esbuild/win32-x64" "0.17.18" 142 | 143 | "js-tokens@^3.0.0 || ^4.0.0": 144 | version "4.0.0" 145 | resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" 146 | integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== 147 | 148 | loose-envify@^1.1.0: 149 | version "1.4.0" 150 | resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" 151 | integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== 152 | dependencies: 153 | js-tokens "^3.0.0 || ^4.0.0" 154 | 155 | react-dom@^18.2.0: 156 | version "18.2.0" 157 | resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-18.2.0.tgz#22aaf38708db2674ed9ada224ca4aa708d821e3d" 158 | integrity sha512-6IMTriUmvsjHUjNtEDudZfuDQUoWXVxKHhlEGSk81n4YFS+r/Kl99wXiwlVXtPBtJenozv2P+hxDsw9eA7Xo6g== 159 | dependencies: 160 | loose-envify "^1.1.0" 161 | scheduler "^0.23.0" 162 | 163 | react@^18.2.0: 164 | version "18.2.0" 165 | resolved "https://registry.yarnpkg.com/react/-/react-18.2.0.tgz#555bd98592883255fa00de14f1151a917b5d77d5" 166 | integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ== 167 | dependencies: 168 | loose-envify "^1.1.0" 169 | 170 | remix-esbuild-override@3.1.0: 171 | version "3.1.0" 172 | resolved "https://registry.yarnpkg.com/remix-esbuild-override/-/remix-esbuild-override-3.1.0.tgz#9f586dd4ded58bdc48920b8a855a6596ce8d2f56" 173 | integrity sha512-K9eIukm1n+K0d2ZPEbRYoj/NHWp3rsa0R9YO/U3bNDnjCVNItJBLSIS5sNqoELLb5kdnbXP2062gJ1yWpjMHrQ== 174 | 175 | scheduler@^0.23.0: 176 | version "0.23.0" 177 | resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.0.tgz#ba8041afc3d30eb206a487b6b384002e4e61fdfe" 178 | integrity sha512-CtuThmgHNg7zIZWAXi3AsyIzA3n4xx7aNyjwC2VJldO2LMVDhFK+63xGqq6CsJH4rTAt6/M+N4GhZiDYPx9eUw== 179 | dependencies: 180 | loose-envify "^1.1.0" 181 | -------------------------------------------------------------------------------- /examples/chakra-ui-cloudflare/.eslintrc.js: -------------------------------------------------------------------------------- 1 | /** @type {import('eslint').Linter.Config} */ 2 | module.exports = { 3 | extends: ["@remix-run/eslint-config", "@remix-run/eslint-config/node"], 4 | }; 5 | -------------------------------------------------------------------------------- /examples/chakra-ui-cloudflare/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /build 5 | /dist 6 | /public/build 7 | /.mf 8 | .env 9 | -------------------------------------------------------------------------------- /examples/chakra-ui-cloudflare/README.md: -------------------------------------------------------------------------------- 1 | # Remix with [Chakra UI](https://chakra-ui.com/) on Cloudflare 2 | 3 | The base template is based on the official [setup document](https://chakra-ui.com/guides/getting-started/remix-guide) and is exactly as it is under the app directory. 4 | This example is for Cloudflare Workers, but it is basically the same for Cloudflare Pages. 5 | 6 | Since @emotion/server depends on Buffer, it cannot run on Cloudflare as is. 7 | 8 | ## Use remix-esbuild-override 9 | 10 | Use remix-esbuild-override and the plugin for polyfill to solve the problem. 11 | 12 | 1. Install and setup `postinstall` 13 | 14 | ```bash 15 | npm install -D remix-esbuild-override @esbuild-plugins/node-globals-polyfill 16 | # or 17 | yarn add -D remix-esbuild-override @esbuild-plugins/node-globals-polyfill 18 | ``` 19 | 20 | Update `scripts > postinstall` in package.json. 21 | 22 | ```json 23 | "scripts": { 24 | "postinstall": "remix-esbuild-override" 25 | } 26 | ``` 27 | 28 | **Run `npm install` or `yarn install` again to run `postinstall`.** 29 | 30 | 2. Update remix.config.js 31 | 32 | ```js 33 | const { withEsbuildOverride } = require("remix-esbuild-override"); 34 | const GlobalsPolyfills = 35 | require("@esbuild-plugins/node-globals-polyfill").default; 36 | 37 | withEsbuildOverride((option, { isServer }) => { 38 | if (isServer) 39 | option.plugins = [ 40 | GlobalsPolyfills({ 41 | buffer: true, 42 | }), 43 | ...option.plugins, 44 | ]; 45 | 46 | return option; 47 | }); 48 | 49 | /** @type {import('@remix-run/dev').AppConfig} */ 50 | module.exports = { 51 | serverBuildTarget: "cloudflare-workers", 52 | server: "./server.js", 53 | devServerBroadcastDelay: 1000, 54 | ignoredRouteFiles: ["**/.*"], 55 | // appDirectory: "app", 56 | // assetsBuildDirectory: "public/build", 57 | // serverBuildPath: "build/index.js", 58 | // publicPath: "/build/", 59 | }; 60 | ``` 61 | 62 | That's all. 63 | 64 | --- 65 | 66 | # Welcome to Remix! 67 | 68 | - [Remix Docs](https://remix.run/docs) 69 | 70 | ## Development 71 | 72 | You will be running two processes during development: 73 | 74 | - The Miniflare server (miniflare is a local environment for Cloudflare Workers) 75 | - The Remix development server 76 | 77 | Both are started with one command: 78 | 79 | ```sh 80 | npm run dev 81 | ``` 82 | 83 | Open up [http://127.0.0.1:8787](http://127.0.0.1:8787) and you should be ready to go! 84 | 85 | If you want to check the production build, you can stop the dev server and run following commands: 86 | 87 | ```sh 88 | npm run build 89 | npm start 90 | ``` 91 | 92 | Then refresh the same URL in your browser (no live reload for production builds). 93 | 94 | ## Deployment 95 | 96 | If you don't already have an account, then [create a cloudflare account here](https://dash.cloudflare.com/sign-up) and after verifying your email address with Cloudflare, go to your dashboard and set up your free custom Cloudflare Workers subdomain. 97 | 98 | Once that's done, you should be able to deploy your app: 99 | 100 | ```sh 101 | npm run deploy 102 | ``` 103 | -------------------------------------------------------------------------------- /examples/chakra-ui-cloudflare/app/context.tsx: -------------------------------------------------------------------------------- 1 | import React, { createContext } from 'react' 2 | 3 | export interface ServerStyleContextData { 4 | key: string 5 | ids: Array 6 | css: string 7 | } 8 | 9 | export const ServerStyleContext = createContext(null) 10 | 11 | export interface ClientStyleContextData { 12 | reset: () => void 13 | } 14 | 15 | export const ClientStyleContext = createContext(null) 16 | -------------------------------------------------------------------------------- /examples/chakra-ui-cloudflare/app/createEmotionCache.ts: -------------------------------------------------------------------------------- 1 | import createCache from "@emotion/cache"; 2 | 3 | export const defaultCache = createEmotionCache(); 4 | 5 | export default function createEmotionCache() { 6 | return createCache({ key: "cha" }); 7 | } 8 | -------------------------------------------------------------------------------- /examples/chakra-ui-cloudflare/app/entry.client.tsx: -------------------------------------------------------------------------------- 1 | import { RemixBrowser } from "@remix-run/react"; 2 | import { ReactNode, startTransition, StrictMode, useState } from "react"; 3 | import { hydrateRoot } from "react-dom/client"; 4 | import { ClientStyleContext } from "./context"; 5 | import createEmotionCache, { defaultCache } from "./createEmotionCache"; 6 | import { CacheProvider } from "@emotion/react"; 7 | 8 | interface ClientCacheProviderProps { 9 | children: ReactNode; 10 | } 11 | 12 | function ClientCacheProvider({ children }: ClientCacheProviderProps) { 13 | const [cache, setCache] = useState(defaultCache); 14 | 15 | function reset() { 16 | setCache(createEmotionCache()); 17 | } 18 | 19 | return ( 20 | 21 | {children} 22 | 23 | ); 24 | } 25 | 26 | function hydrate() { 27 | startTransition(() => { 28 | hydrateRoot( 29 | document, 30 | 31 | 32 | 33 | 34 | 35 | ); 36 | }); 37 | } 38 | 39 | if (window.requestIdleCallback) { 40 | window.requestIdleCallback(hydrate); 41 | } else { 42 | // Safari doesn't support requestIdleCallback 43 | // https://caniuse.com/requestidlecallback 44 | window.setTimeout(hydrate, 1); 45 | } 46 | -------------------------------------------------------------------------------- /examples/chakra-ui-cloudflare/app/entry.server.tsx: -------------------------------------------------------------------------------- 1 | import type { EntryContext } from "@remix-run/cloudflare"; 2 | import { RemixServer } from "@remix-run/react"; 3 | import { renderToString } from "react-dom/server"; 4 | import createEmotionCache from "~/createEmotionCache"; 5 | import createEmotionServer from "@emotion/server/create-instance"; 6 | import { ServerStyleContext } from "~/context"; 7 | import { CacheProvider } from "@emotion/react"; 8 | 9 | export default function handleRequest( 10 | request: Request, 11 | responseStatusCode: number, 12 | responseHeaders: Headers, 13 | remixContext: EntryContext 14 | ) { 15 | const cache = createEmotionCache() 16 | const { extractCriticalToChunks } = createEmotionServer(cache) 17 | 18 | const html = renderToString( 19 | 20 | 21 | 22 | 23 | , 24 | ) 25 | 26 | const chunks = extractCriticalToChunks(html) 27 | 28 | const markup = renderToString( 29 | 30 | 31 | 32 | 33 | , 34 | ) 35 | 36 | responseHeaders.set('Content-Type', 'text/html') 37 | 38 | return new Response(`${markup}`, { 39 | status: responseStatusCode, 40 | headers: responseHeaders, 41 | }) 42 | } 43 | -------------------------------------------------------------------------------- /examples/chakra-ui-cloudflare/app/root.tsx: -------------------------------------------------------------------------------- 1 | import type { LinksFunction, MetaFunction } from "@remix-run/cloudflare"; 2 | import { 3 | Links, 4 | LiveReload, 5 | Meta, 6 | Outlet, 7 | Scripts, 8 | ScrollRestoration, 9 | } from "@remix-run/react"; 10 | import { ServerStyleContext, ClientStyleContext } from "~/context"; 11 | import { withEmotionCache } from "@emotion/react"; 12 | import { useContext, useEffect } from "react"; 13 | import { ChakraProvider } from "@chakra-ui/react"; 14 | 15 | export const meta: MetaFunction = () => ({ 16 | charset: "utf-8", 17 | title: "New Remix App", 18 | viewport: "width=device-width,initial-scale=1", 19 | }); 20 | 21 | export let links: LinksFunction = () => { 22 | return [ 23 | { rel: "preconnect", href: "https://fonts.googleapis.com" }, 24 | { rel: "preconnect", href: "https://fonts.gstatic.com" }, 25 | { 26 | rel: "stylesheet", 27 | href: "https://fonts.googleapis.com/css2?family=Poppins:ital,wght@0,300;0,400;0,500;0,600;0,700;0,800;1,300;1,400;1,500;1,600;1,700;1,800&display=swap", 28 | }, 29 | ]; 30 | }; 31 | 32 | interface DocumentProps { 33 | children: React.ReactNode; 34 | } 35 | 36 | const Document = withEmotionCache( 37 | ({ children }: DocumentProps, emotionCache) => { 38 | const serverStyleData = useContext(ServerStyleContext); 39 | const clientStyleData = useContext(ClientStyleContext); 40 | 41 | // Only executed on client 42 | useEffect(() => { 43 | // re-link sheet container 44 | emotionCache.sheet.container = document.head; 45 | // re-inject tags 46 | const tags = emotionCache.sheet.tags; 47 | emotionCache.sheet.flush(); 48 | tags.forEach((tag) => { 49 | (emotionCache.sheet as any)._insertTag(tag); 50 | }); 51 | // reset cache to reapply global styles 52 | clientStyleData?.reset(); 53 | }, []); 54 | 55 | return ( 56 | 57 | 58 | 59 | 60 | {serverStyleData?.map(({ key, ids, css }) => ( 61 |