├── .prettierrc ├── .github ├── CODEOWNERS ├── .kodiak.toml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md ├── workflows │ └── labeller.yml └── PULL_REQUEST_TEMPLATE.md ├── env.d.ts ├── public └── favicon.ico ├── .gitignore ├── remix.init ├── edge │ ├── app │ │ ├── entry.server.tsx │ │ └── routes │ │ │ └── _index.tsx │ ├── vite.config.ts │ ├── netlify.toml │ └── README.md ├── package.json ├── functions │ ├── vite.config.ts │ ├── netlify.toml │ └── README.md └── index.js ├── app ├── root.tsx └── routes │ └── _index.tsx ├── tsconfig.json ├── package.json ├── README.md └── .eslintrc.cjs /.prettierrc: -------------------------------------------------------------------------------- 1 | {} 2 | -------------------------------------------------------------------------------- /.github/CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @netlify/ecosystem-pod-frameworks 2 | -------------------------------------------------------------------------------- /env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | /// 3 | -------------------------------------------------------------------------------- /public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/netlify/remix-template/HEAD/public/favicon.ico -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | /.cache 4 | /public/build 5 | /build 6 | .env 7 | 8 | # Local Netlify folder 9 | .netlify 10 | .DS_Store 11 | -------------------------------------------------------------------------------- /remix.init/edge/app/entry.server.tsx: -------------------------------------------------------------------------------- 1 | // @ts-expect-error virtual module 2 | // eslint-disable-next-line import/no-unresolved 3 | export { default } from "virtual:netlify-server-entry"; 4 | -------------------------------------------------------------------------------- /.github/.kodiak.toml: -------------------------------------------------------------------------------- 1 | version = 1 2 | 3 | [merge.automerge_dependencies] 4 | versions = ["minor", "patch"] 5 | usernames = ["renovate"] 6 | 7 | [approve] 8 | auto_approve_usernames = ["renovate"] 9 | -------------------------------------------------------------------------------- /remix.init/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remix.init", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "license": "MIT", 6 | "private": true, 7 | "dependencies": { 8 | "@clack/prompts": "^0.7.0", 9 | "@npmcli/package-json": "^4.0.1", 10 | "argh": "^1.0.0", 11 | "execa": "5.1.1" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /remix.init/edge/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | import { netlifyPlugin } from "@netlify/remix-edge-adapter/plugin"; 5 | 6 | export default defineConfig({ 7 | plugins: [remix(), netlifyPlugin(), tsconfigPaths()], 8 | }); 9 | -------------------------------------------------------------------------------- /remix.init/functions/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { vitePlugin as remix } from "@remix-run/dev"; 2 | import { defineConfig } from "vite"; 3 | import tsconfigPaths from "vite-tsconfig-paths"; 4 | import { netlifyPlugin } from "@netlify/remix-adapter/plugin"; 5 | 6 | export default defineConfig({ 7 | plugins: [remix(), netlifyPlugin(), tsconfigPaths()], 8 | }); 9 | -------------------------------------------------------------------------------- /remix.init/edge/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "npm run build" 3 | publish = "build/client" 4 | 5 | [dev] 6 | command = "npm run dev" 7 | framework = "vite" 8 | 9 | # Set immutable caching for static files, because they have fingerprinted filenames 10 | 11 | [[headers]] 12 | for = "/build/*" 13 | 14 | [headers.values] 15 | 16 | "Cache-Control" = "public, max-age=31560000, immutable" 17 | -------------------------------------------------------------------------------- /remix.init/functions/netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | command = "npm run build" 3 | publish = "build/client" 4 | 5 | [dev] 6 | command = "npm run dev" 7 | framework = "vite" 8 | 9 | # Set immutable caching for static files, because they have fingerprinted filenames 10 | 11 | [[headers]] 12 | for = "/build/*" 13 | 14 | [headers.values] 15 | 16 | "Cache-Control" = "public, max-age=31560000, immutable" 17 | -------------------------------------------------------------------------------- /app/root.tsx: -------------------------------------------------------------------------------- 1 | import { 2 | Links, 3 | Meta, 4 | Outlet, 5 | Scripts, 6 | ScrollRestoration, 7 | } from "@remix-run/react"; 8 | 9 | export default function App() { 10 | return ( 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["env.d.ts", "**/*.ts", "**/*.tsx", "netlify-edge-plugin.ts"], 3 | "compilerOptions": { 4 | "lib": ["DOM", "DOM.Iterable", "ES2022"], 5 | "isolatedModules": true, 6 | "esModuleInterop": true, 7 | "jsx": "react-jsx", 8 | "module": "ESNext", 9 | "moduleResolution": "Bundler", 10 | "resolveJsonModule": true, 11 | "target": "ES2022", 12 | "strict": true, 13 | "allowJs": true, 14 | "skipLibCheck": true, 15 | "forceConsistentCasingInFileNames": true, 16 | "baseUrl": ".", 17 | "paths": { 18 | "~/*": ["./app/*"] 19 | }, 20 | // Vite takes care of building everything, not tsc. 21 | "noEmit": true 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/workflows/labeller.yml: -------------------------------------------------------------------------------- 1 | name: Label PR 2 | on: 3 | pull_request: 4 | types: [opened, edited] 5 | 6 | jobs: 7 | label-pr: 8 | if: github.event_name == 'pull_request' && github.event.pull_request.head.repo.fork == false 9 | runs-on: ubuntu-latest 10 | strategy: 11 | matrix: 12 | pr: 13 | [ 14 | { prefix: 'fix', type: 'bug' }, 15 | { prefix: 'chore', type: 'chore' }, 16 | { prefix: 'test', type: 'chore' }, 17 | { prefix: 'ci', type: 'chore' }, 18 | { prefix: 'feat', type: 'feature' }, 19 | { prefix: 'security', type: 'security' }, 20 | ] 21 | steps: 22 | - uses: netlify/pr-labeler-action@v1.1.0 23 | if: startsWith(github.event.pull_request.title, matrix.pr.prefix) 24 | with: 25 | token: '${{ secrets.GITHUB_TOKEN }}' 26 | label: 'type: ${{ matrix.pr.type }}' 27 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /app/routes/_index.tsx: -------------------------------------------------------------------------------- 1 | import type { MetaFunction } from "@remix-run/node"; 2 | 3 | export const meta: MetaFunction = () => { 4 | return [ 5 | { title: "New Remix App" }, 6 | { name: "description", content: "Welcome to Remix!" }, 7 | ]; 8 | }; 9 | 10 | export default function Index() { 11 | return ( 12 |
13 |

Welcome to Remix

14 | 39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /remix.init/edge/app/routes/_index.tsx: -------------------------------------------------------------------------------- 1 | import type { MetaFunction } from "@netlify/remix-runtime"; 2 | 3 | export const meta: MetaFunction = () => { 4 | return [ 5 | { title: "New Remix App" }, 6 | { name: "description", content: "Welcome to Remix!" }, 7 | ]; 8 | }; 9 | 10 | export default function Index() { 11 | return ( 12 |
13 |

Welcome to Remix

14 | 39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "remix-app", 3 | "private": true, 4 | "sideEffects": false, 5 | "type": "module", 6 | "scripts": { 7 | "build": "remix init && remix vite:build", 8 | "dev": "remix init && remix vite:dev", 9 | "lint": "eslint --ignore-path .gitignore --cache --cache-location ./node_modules/.cache/eslint .", 10 | "start": "remix init && netlify serve", 11 | "typecheck": "tsc" 12 | }, 13 | "dependencies": { 14 | "@netlify/edge-functions": "^2.3.1", 15 | "@netlify/functions": "^2.6.0", 16 | "@netlify/remix-adapter": "^2.3.1", 17 | "@netlify/remix-edge-adapter": "^3.2.1", 18 | "@netlify/remix-runtime": "^2.2.0", 19 | "@remix-run/node": "*", 20 | "@remix-run/react": "*", 21 | "@remix-run/serve": "*", 22 | "isbot": "^4.1.0" 23 | }, 24 | "devDependencies": { 25 | "@remix-run/dev": "*", 26 | "@types/react": "^18.2.20", 27 | "@types/react-dom": "^18.2.7", 28 | "@typescript-eslint/eslint-plugin": "^6.7.4", 29 | "eslint": "^8.38.0", 30 | "eslint-config-prettier": "^9.0.0", 31 | "eslint-import-resolver-typescript": "^3.6.1", 32 | "eslint-plugin-import": "^2.28.1", 33 | "eslint-plugin-jsx-a11y": "^6.7.1", 34 | "eslint-plugin-react": "^7.33.2", 35 | "eslint-plugin-react-hooks": "^4.6.0", 36 | "typescript": "^5.1.6", 37 | "vite": "^5.4.8", 38 | "vite-tsconfig-paths": "^4.2.1" 39 | }, 40 | "engines": { 41 | "node": ">=18.0.0" 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Netlify Remix Template 2 | 3 | Welcome to the Netlify Remix Template project. If you were expecting this to be your site, run `remix init` in the root of this project to get started. 4 | 5 | To use the template, run 6 | 7 | ```bash 8 | npx create-remix@latest --template netlify/remix-template 9 | ``` 10 | 11 | This project includes: 12 | 13 | - Netlify Functions template for Remix sites 14 | - Netlify Edge Functions template for Remix sites 15 | 16 | From the `create-remix` command, you may pass `--netlify-edge` or `--no-netlify-edge` to generate a template that uses Netlify Edge or Serverless functions explicitly. Without passing this option, the create workflow will ask you which you would prefer. 17 | 18 | ## Development 19 | 20 | There is no need to run `npm install` as this is a template. The Remix CLI will install the dependencies for you. Make changes to files as you see fit. If there are transformations for files for either the Netlify Functions or Netlify Edge Functions template, make the appropriate changes to the `remix.init/index.js` file. 21 | 22 | If you're new to Remix stacks and the remix.init concept, see the official [Remix Stacks](https://remix.run/stacks) documentation. 23 | 24 | ### Testing your changes 25 | 26 | Run 27 | 28 | ```bash 29 | npx create-remix@latest --template ./remix-template 30 | ``` 31 | 32 | to test your changes to the template. Follow the steps the Remix CLI prompts you with to create a new project. Ensure to test for both the Netlify Functions template and the Netlify Edge Functions template. 33 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | ## Related Tickets & Documents 4 | 5 | 13 | 14 | - Related Issue # 15 | - Closes # 16 | 17 | ## QA Instructions, Screenshots, Recordings 18 | 19 | _Please replace this line with instructions on how to test your changes_ 20 | 21 | For us to review and ship your PR efficiently, please perform the following steps: 22 | 23 | - [ ] Open a [bug/issue](https://github.com/netlify/remix-edge-template/issues/new/choose) before writing your code 🧑‍💻. This ensures we 24 | can discuss the changes and get feedback from everyone that should be involved. If you\`re fixing a typo or 25 | something that\`s on fire 🔥 (e.g. incident related), you can skip this step. 26 | - [ ] Read the [contribution guidelines](../blob/main/CONTRIBUTING.md) 📖. This ensures your code follows our style 27 | guide and passes our tests. 28 | - [ ] Update or add tests (if any source code was changed or added) 🧪 29 | - [ ] Update or add documentation (if features were changed or added) 📝 30 | - [ ] Make sure the status checks below are successful ✅ 31 | 32 | **A picture of a cute animal (not mandatory, but encouraged)** 33 | -------------------------------------------------------------------------------- /remix.init/edge/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - [Remix Docs](https://remix.run/docs) 4 | - [Netlify Functions Overview](https://docs.netlify.com/functions/overview) 5 | 6 | ## Netlify Setup 7 | 8 | 1. Install the [Netlify CLI](https://docs.netlify.com/cli/get-started/): 9 | 10 | ```sh 11 | npm i -g netlify-cli 12 | ``` 13 | 14 | If you have previously installed the Netlify CLI, you should update it to the latest version: 15 | 16 | ```sh 17 | npm i -g netlify-cli@latest 18 | ``` 19 | 20 | 2. Sign up and log in to Netlify: 21 | 22 | ```sh 23 | netlify login 24 | ``` 25 | 26 | 3. Create a new site: 27 | 28 | ```sh 29 | netlify init 30 | ``` 31 | 32 | ## Development 33 | 34 | Ensure all packages are installed by running: 35 | 36 | ```sh 37 | npm install 38 | ``` 39 | 40 | Run 41 | 42 | ```sh 43 | netlify dev 44 | ``` 45 | 46 | Open up [http://localhost:8888](http://localhost:8888), and you're ready to go! 47 | 48 | ### Serve your site locally 49 | 50 | To serve your site locally in a production-like environment, run 51 | 52 | ```sh 53 | netlify serve 54 | ``` 55 | 56 | Your site will be available at [http://localhost:8888](http://localhost:8888). Note that it will not auto-reload when you make changes. 57 | 58 | ## Deployment 59 | 60 | There are two ways to deploy your app to Netlify, you can either link your app to your git repo and have it auto deploy changes to Netlify, or you can deploy your app manually. If you've followed the setup instructions already, all you need to do is run this: 61 | 62 | ```sh 63 | # preview deployment 64 | netlify deploy --build 65 | 66 | # production deployment 67 | netlify deploy --build --prod 68 | ``` 69 | -------------------------------------------------------------------------------- /remix.init/functions/README.md: -------------------------------------------------------------------------------- 1 | # Welcome to Remix! 2 | 3 | - [Remix Docs](https://remix.run/docs) 4 | - [Netlify Functions Overview](https://docs.netlify.com/functions/overview) 5 | 6 | ## Netlify Setup 7 | 8 | 1. Install the [Netlify CLI](https://docs.netlify.com/cli/get-started/): 9 | 10 | ```sh 11 | npm i -g netlify-cli 12 | ``` 13 | 14 | If you have previously installed the Netlify CLI, you should update it to the latest version: 15 | 16 | ```sh 17 | npm i -g netlify-cli@latest 18 | ``` 19 | 20 | 2. Sign up and log in to Netlify: 21 | 22 | ```sh 23 | netlify login 24 | ``` 25 | 26 | 3. Create a new site: 27 | 28 | ```sh 29 | netlify init 30 | ``` 31 | 32 | ## Development 33 | 34 | Ensure all packages are installed by running: 35 | 36 | ```sh 37 | npm install 38 | ``` 39 | 40 | Run 41 | 42 | ```sh 43 | netlify dev 44 | ``` 45 | 46 | Open up [http://localhost:8888](http://localhost:8888), and you're ready to go! 47 | 48 | ### Serve your site locally 49 | 50 | To serve your site locally in a production-like environment, run 51 | 52 | ```sh 53 | netlify serve 54 | ``` 55 | 56 | Your site will be available at [http://localhost:8888](http://localhost:8888). Note that it will not auto-reload when you make changes. 57 | 58 | ## Deployment 59 | 60 | There are two ways to deploy your app to Netlify, you can either link your app to your git repo and have it auto deploy changes to Netlify, or you can deploy your app manually. If you've followed the setup instructions already, all you need to do is run this: 61 | 62 | ```sh 63 | # preview deployment 64 | netlify deploy --build 65 | 66 | # production deployment 67 | netlify deploy --build --prod 68 | ``` 69 | -------------------------------------------------------------------------------- /.eslintrc.cjs: -------------------------------------------------------------------------------- 1 | /** 2 | * This is intended to be a basic starting point for linting in your app. 3 | * It relies on recommended configs out of the box for simplicity, but you can 4 | * and should modify this configuration to best suit your team's needs. 5 | */ 6 | 7 | /** @type {import('eslint').Linter.Config} */ 8 | module.exports = { 9 | root: true, 10 | parserOptions: { 11 | ecmaVersion: "latest", 12 | sourceType: "module", 13 | ecmaFeatures: { 14 | jsx: true, 15 | }, 16 | }, 17 | env: { 18 | browser: true, 19 | commonjs: true, 20 | es6: true, 21 | }, 22 | 23 | // Base config 24 | extends: ["eslint:recommended"], 25 | 26 | overrides: [ 27 | // React 28 | { 29 | files: ["**/*.{js,jsx,ts,tsx}"], 30 | plugins: ["react", "jsx-a11y"], 31 | extends: [ 32 | "plugin:react/recommended", 33 | "plugin:react/jsx-runtime", 34 | "plugin:react-hooks/recommended", 35 | "plugin:jsx-a11y/recommended", 36 | ], 37 | settings: { 38 | react: { 39 | version: "detect", 40 | }, 41 | formComponents: ["Form"], 42 | linkComponents: [ 43 | { name: "Link", linkAttribute: "to" }, 44 | { name: "NavLink", linkAttribute: "to" }, 45 | ], 46 | "import/resolver": { 47 | typescript: {}, 48 | }, 49 | }, 50 | }, 51 | 52 | // Typescript 53 | { 54 | files: ["**/*.{ts,tsx}"], 55 | plugins: ["@typescript-eslint", "import"], 56 | parser: "@typescript-eslint/parser", 57 | settings: { 58 | "import/internal-regex": "^~/", 59 | "import/resolver": { 60 | node: { 61 | extensions: [".ts", ".tsx"], 62 | }, 63 | typescript: { 64 | alwaysTryTypes: true, 65 | }, 66 | }, 67 | }, 68 | extends: [ 69 | "plugin:@typescript-eslint/recommended", 70 | "plugin:import/recommended", 71 | "plugin:import/typescript", 72 | ], 73 | }, 74 | 75 | // Node 76 | { 77 | files: [".eslintrc.js"], 78 | env: { 79 | node: true, 80 | }, 81 | }, 82 | ], 83 | }; 84 | -------------------------------------------------------------------------------- /remix.init/index.js: -------------------------------------------------------------------------------- 1 | const { 2 | intro, 3 | outro, 4 | select, 5 | isCancel, 6 | cancel, 7 | spinner, 8 | } = require("@clack/prompts"); 9 | const argh = require("argh"); 10 | const process = require("node:process"); 11 | const { relative, join, dirname } = require("node:path"); 12 | const fs = require("fs/promises"); 13 | const PackageJson = require("@npmcli/package-json"); 14 | const execa = require("execa"); 15 | 16 | const foldersToRemove = [".github"]; 17 | 18 | const packagesToRemove = { 19 | edge: ["@netlify/remix-adapter", "@netlify/functions"], 20 | functions: [ 21 | "@netlify/edge-functions", 22 | "@netlify/remix-edge-adapter", 23 | "@netlify/remix-runtime", 24 | ], 25 | }; 26 | 27 | async function mergeDirs(src, dest) { 28 | await fs.mkdir(dest, { recursive: true }); 29 | let entries = await fs.readdir(src, { withFileTypes: true }); 30 | 31 | for (let entry of entries) { 32 | const srcPath = join(src, entry.name); 33 | const destPath = join(dest, entry.name); 34 | 35 | if (entry.isDirectory()) { 36 | await mergeDirs(srcPath, destPath); 37 | } else { 38 | await fs.mkdir(dirname(destPath), { recursive: true }); 39 | await fs.copyFile(srcPath, destPath); 40 | } 41 | } 42 | } 43 | 44 | async function copyTemplateFiles(rootDirectory, useEdge) { 45 | const source = join( 46 | rootDirectory, 47 | "remix.init", 48 | useEdge ? "edge" : "functions" 49 | ); 50 | await mergeDirs(source, rootDirectory); 51 | } 52 | 53 | async function removeUpdatePackageJson(directory, dependencies) { 54 | const packageJson = await PackageJson.load(directory); 55 | 56 | const { dependencies: currentDependencies = {}, scripts } = 57 | packageJson.content; 58 | 59 | // Remove the auto-init command from the scripts 60 | for (const script of ["build", "start", "dev"]) { 61 | scripts[script] = scripts[script]?.replace("remix init && ", ""); 62 | } 63 | 64 | packageJson.update({ 65 | dependencies: Object.fromEntries( 66 | Object.entries(currentDependencies).filter( 67 | ([dependency]) => !dependencies.includes(dependency) 68 | ) 69 | ), 70 | }); 71 | 72 | await packageJson.save(); 73 | } 74 | 75 | async function removeNonTemplateFiles({ rootDirectory, folders }) { 76 | try { 77 | await Promise.allSettled( 78 | folders.map((folder) => 79 | fs.rm(join(rootDirectory, folder), { recursive: true, force: true }) 80 | ) 81 | ); 82 | } catch (e) { 83 | console.log( 84 | `Unable to remove folders ${folders.join( 85 | ", " 86 | )}. You can remove them manually.` 87 | ); 88 | } 89 | } 90 | 91 | async function installAdditionalDependencies({ 92 | rootDirectory, 93 | packageManager, 94 | }) { 95 | try { 96 | console.log(`Installing additional dependencies with ${packageManager}.`); 97 | const result = await execa(packageManager, ["install"], { 98 | cwd: rootDirectory, 99 | stdio: "ignore", 100 | }); 101 | if (result.failed) { 102 | return false; 103 | } 104 | } catch (e) { 105 | return false; 106 | } 107 | return true; 108 | } 109 | 110 | async function shouldUseEdge(rootDirectory) { 111 | const { "netlify-edge": netlifyEdge } = argh.argv; 112 | 113 | let useEdge = netlifyEdge; 114 | 115 | if (useEdge === undefined) { 116 | const projectType = await select({ 117 | message: "Run your Remix site with:", 118 | options: [ 119 | { 120 | value: "functions", 121 | label: "Netlify Functions", 122 | hint: "A Node-based runtime, running in one region", 123 | }, 124 | { 125 | value: "edge", 126 | label: "Netlify Edge Functions", 127 | hint: "A web-based runtime, running at the edge", 128 | }, 129 | ], 130 | }); 131 | if (isCancel(projectType)) { 132 | cancel( 133 | `Project setup cancelled. Run remix init inside ${ 134 | relative(process.cwd(), rootDirectory) || "this folder" 135 | } to complete setup.` 136 | ); 137 | process.exit(1); 138 | } 139 | useEdge = projectType === "edge"; 140 | } 141 | return useEdge; 142 | } 143 | 144 | async function main({ rootDirectory, packageManager }) { 145 | intro(`Welcome to Remix on Netlify`); 146 | const useEdge = await shouldUseEdge(rootDirectory); 147 | const spin = spinner(); 148 | spin.start("Setting up your project"); 149 | await copyTemplateFiles(rootDirectory, useEdge); 150 | await removeNonTemplateFiles({ 151 | rootDirectory, 152 | folders: foldersToRemove, 153 | }); 154 | 155 | spin.stop("Setup complete"); 156 | 157 | spin.start("Updating dependencies"); 158 | await removeUpdatePackageJson( 159 | rootDirectory, 160 | packagesToRemove[useEdge ? "edge" : "functions"] 161 | ); 162 | 163 | const result = await installAdditionalDependencies({ 164 | rootDirectory, 165 | packageManager, 166 | }); 167 | 168 | if (!result) { 169 | spin.stop("Failed"); 170 | 171 | cancel( 172 | `Failed to install additional dependencies. Run "${packageManager} install" inside "${relative( 173 | process.cwd(), 174 | rootDirectory 175 | )}" to complete setup.` 176 | ); 177 | } else { 178 | spin.stop("Dependencies updated"); 179 | outro(`Project setup for Netlify complete. Happy Remixing!`); 180 | } 181 | } 182 | 183 | module.exports = main; 184 | --------------------------------------------------------------------------------