- Create Project Structure
- Vite Configuration
- HTML Entry Point
- Render Function
- Start Development Server
- Components
- Styling
- Create Signal
- Create Effect
- Create Resource
- Deploy
- Netlify
- Vercel
- Cloudflare Pages
- Edgio
- Solid Start
- Client and Server Entry
- Root
- Solid Start Todos Route
- Solid Start Todo Data
- Todo CSS
- Solid Start Deploy
- Netlify
- Vercel
mkdir ajcwebdev-solid
cd ajcwebdev-solid
pnpm init
pnpm add -D solid-js \
@solidjs/meta @solidjs/router \
solid-start solid-start-node \
vite vite-plugin-solid undici \
vercel netlify-cli wrangler @layer0/cli \
@babel/core typescript webpack
echo 'node_modules\ndist\n.DS_Store\n.netlify\nnetlify\n.vercel\n.layer0\n.solid\n.env\npackage-lock.json' > .gitignore
Add vite
scripts to package.json
.
{
"name": "ajcwebdev-solid",
"version": "1.0.0",
"description": "An example SolidJS application deployed on Netlify, Vercel, Cloudflare Pages, and Edgio",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"serve": "vite preview"
},
"keywords": [ "SolidJS", "Netlify", "Vercel", "Cloudflare", "Edgio" ],
"author": "FIRST_NAME LAST_NAME",
"license": "MIT",
"devDependencies": {
"@solidjs/meta": "^0.28.0",
"@solidjs/router": "^0.4.3",
"netlify-cli": "^11.8.2",
"solid-js": "^1.5.5",
"solid-start": "0.1.0-alpha.104",
"solid-start-node": "0.1.0-alpha.104",
"undici": "^5.10.0",
"vercel": "^28.4.1",
"vite": "^3.1.3",
"vite-plugin-solid": "^2.3.6",
"wrangler": "^2.1.6"
}
}
Create a vite.config.js
file. This will allow us to define our Vite Configuration with the Solid Plugin.
echo > vite.config.js
Import solidPlugin
from vite-plugin-solid
and add it to the plugins
array inside Vite's defineConfig
helper.
// vite.config.js
import { defineConfig } from "vite"
import solidPlugin from "vite-plugin-solid"
export default defineConfig({
plugins: [solidPlugin()]
})
Create an index.html
file for our HTML entry point.
echo > index.html
The root Solid component will be imported as an ESM module from /src/root.jsx
and set to the src
attribute on script
.
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<title>A First Look at Solid</title>
</head>
<body>
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
<script src="/src/root.jsx" type="module"></script>
</body>
</html>
mkdir src
echo > src/root.jsx
// src/root.jsx
/* @refresh reload */
import { render } from "solid-js/web"
function App() {
return (
<div>
<header>
<h1>A First Look at Solid</h1>
<a href="https://github.com/solidjs/solid">
Learn Solid
</a>
</header>
</div>
)
}
render(
() => <App />,document.getElementById('root')
)
pnpm dev # or npm run dev | yarn dev
Open localhost:5173 to view the running application in your browser. The page will reload if you make edits.
mkdir src/routes
echo > src/routes/index.jsx
// src/routes/index.jsx
export default function App() {
return (
<div class="App">
<header class="header">
<h1>A First Look at Solid</h1>
<a class="link" href="https://github.com/solidjs/solid">
Learn Solid
</a>
</header>
</div>
)
}
echo > src/root.css
/* src/root.css */
body {
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.App {
text-align: center;
}
.header {
background-color: #282c34;
min-height: 100vh;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: calc(10px + 2vmin);
color: white;
}
.link {
color: #b318f0;
}
Import App
component into root.jsx
file.
// src/root.jsx
/* @refresh reload */
import { render } from "solid-js/web"
import App from "./routes/index"
import "./root.css"
render(
() => <App />,document.getElementById('root')
)
mkdir src/components
echo > src/components/Counter.jsx
// src/components/Counter.jsx
import { createSignal } from "solid-js"
export default function Counter() {
const [count, setCount] = createSignal(0)
setInterval(() => setCount(count() + 1), 1000)
return (
<>Count: {count()}</>
)
}
// src/routes/index.jsx
import Counter from "../components/Counter"
export default function App() {
return (
<div class="App">
<header class="header">
<h1>A First Look at Solid</h1>
<a class="link" href="https://github.com/solidjs/solid">
Learn Solid
</a>
<Counter />
</header>
</div>
)
}
// src/components/Counter.jsx
import { createSignal, createEffect } from "solid-js"
export default function Counter() {
const [count, setCount] = createSignal(0)
createEffect(() => count())
return (
<>
<button onClick={() => setCount(count() + 1)}>
Click Me
</button>
<div>The count is now: {count()}</div>
</>
)
}
Rewrite onMount
to createResource
.
echo > src/components/Users.jsx
// src/components/Users.jsx
import { createSignal, onMount, For } from "solid-js"
export default function Users() {
const [users, setUsers] = createSignal([])
onMount(async () => {
const res = await fetch(`https://jsonplaceholder.typicode.com/users?_limit=5`)
setUsers(await res.json())
})
return (
<>
<For each={users()} fallback={<p>Loading...</p>}>
{user => <div>{user.name}</div>}
</For>
</>
)
}
// src/routes/index.jsx
import Counter from "../components/Counter"
import Users from "../components/Users"
export default function App() {
return (
<div class="App">
<header class="header">
<h1>A First Look at Solid</h1>
<a class="link" href="https://github.com/solidjs/solid">
Learn Solid
</a>
<Counter />
<Users />
</header>
</div>
)
}
You can deploy the dist
folder to any static host provider.
pnpm build
git init
git add .
git commit -m "solid"
gh repo create ajcwebdev-solid \
--description="An example SolidJS application deployed on Netlify, Vercel, Cloudflare Pages, and Edgio" \
--public \
--push \
--source=. \
--remote=upstream
echo > netlify.toml
# netlify.toml
[build]
command = "npm run build"
publish = "dist"
pnpm ntl login
pnpm ntl init
? What would you like to do? + Create & configure a new site
? Team: Anthony Campolo's team
? Site name (you can change it later): ajcwebdev-solid
Site Created
Admin URL: https://app.netlify.com/sites/ajcwebdev-solid
URL: https://ajcwebdev-solid.netlify.app
Site ID: xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Linked to ajcwebdev-solid
? Your build command (hugo build/yarn run build/etc): npm run build
? Directory to deploy (blank for current dir): dist
Open ajcwebdev-solid.netlify.app.
echo > vercel.json
{
"buildCommand": "pnpm build",
"outputDirectory": "dist",
"devCommand": "pnpm dev",
"installCommand": "pnpm install"
}
pnpm vercel login
pnpm vercel git connect --yes
pnpm vercel --yes --prod
Open ajcwebdev-solid.vercel.app.
pnpm wrangler login
pnpm wrangler pages project create ajcwebdev-solid \
--production-branch production
✨ Successfully created the 'ajcwebdev-solid' project. It will be available
at https://ajcwebdev-solid.pages.dev/ once you create your first deployment.
To deploy a folder of assets, run 'wrangler pages publish [directory]'.
Retrieving cached values for userId from node_modules/.cache/wrangler
pnpm wrangler pages publish dist \
--project-name ajcwebdev-solid \
--branch production
Retrieving cached values for account_id and project_name from node_modules/.cache/wrangler
✨ Success! Uploaded 3 files (1.42 sec)
✨ Deployment complete! Take a peek over at https://6e2dfc90.ajcwebdev-solid.pages.dev
Open ajcwebdev-solid.pages.dev.
pnpm 0 login
pnpm 0 init --name ajcwebdev-solid \
--environment production
// routes.js
import { Router } from "@layer0/core/router"
export default new Router()
.noIndexPermalink()
.static('dist', ({ cache }) => {
cache({
edge: {
maxAgeSeconds: 60 * 60 * 60 * 365,
forcePrivateCaching: true,
},
browser: {
maxAgeSeconds: 0,
serviceWorkerSeconds: 60 * 60 * 24,
},
})
})
.fallback(({ appShell }) => {
appShell('dist/index.html')
})
mv layer0.config.js layer0.config.cjs
mv routes.js routes.cjs
pnpm 0 deploy --site ajcwebdev-solid
🖥 Layer0 Developer Console:
https://app.layer0.co/ajcwebdev/ajcwebdev-solid/env/default/builds/1
🔗 Permalink:
https://ajcwebdev-ajcwebdev-solid-main-1.free.layer0-perma.link
🌎 Edge:
https://ajcwebdev-ajcwebdev-solid-default.layer0-limelight.link
Open ajcwebdev-ajcwebdev-solid-default.layer0-limelight.link.
{
"type": "module",
"scripts": {
"dev": "solid-start dev",
"build": "solid-start build",
"start": "solid-start start"
},
}
// vite.config.js
import { defineConfig } from "vite"
import solid from "solid-start/vite"
// import solidPlugin from "vite-plugin-solid"
export default defineConfig({
plugins: [solid()]
// plugins: [solidPlugin()]
})
echo > src/entry-client.jsx
echo > src/entry-server.jsx
// src/entry-client.jsx
import { mount, StartClient } from "solid-start/entry-client"
mount(
() => <StartClient />, document
)
// src/entry-server.jsx
import { StartServer, createHandler, renderAsync } from "solid-start/entry-server"
export default createHandler(
renderAsync((event) => <StartServer event={event} />)
)
// src/root.jsx
// @refresh reload
import { Suspense } from "solid-js"
import {
Body, ErrorBoundary, FileRoutes, Head, Html, Meta, Routes, Scripts
} from "solid-start"
import "./root.css"
export default function Root() {
return (
<Html lang="en">
<Head>
<Meta charset="utf-8" />
<Meta name="viewport" content="width=device-width, initial-scale=1" />
</Head>
<Body>
<ErrorBoundary>
<Suspense>
<Routes>
<FileRoutes />
</Routes>
</Suspense>
</ErrorBoundary>
<Scripts />
</Body>
</Html>
)
}
Check that everything still displays as expected.
pnpm dev
Open localhost:3000.
pnpm add -D solid-start-netlify
# netlify.toml
[build]
command = "npm run build"
publish = "netlify"
// vite.config.js
import { defineConfig } from "vite"
import solid from "solid-start/vite"
import netlify from "solid-start-netlify"
export default defineConfig({
plugins: [solid({ adapter: netlify({ edge: true }) })]
})
Return to ajcwebdev-solid.netlify.app.
pnpm add -D solid-start-vercel
pnpm vercel env add ENABLE_VC_BUILD