### Run Full Setup Script Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/README.md Execute the comprehensive setup script to install dependencies, reset the database, validate the project, prime cache data, install Playwright browsers, and run end-to-end tests. This script ensures the project is ready for development. ```bash npm run setup -s ``` -------------------------------- ### Basic JavaScript Project Setup and Testing Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/how-i-learn-an-open-source-codebase.mdx Standard commands for setting up a JavaScript project, installing dependencies, and running tests. Ensure tests pass before making changes. ```bash npm install ``` ```bash npm test ``` -------------------------------- ### Project Setup and Development Commands Source: https://context7.com/kentcdodds/kentcdodds.com/llms.txt Commands for cloning the repository, setting up the environment, installing dependencies, running the development server, and various testing, quality, build, and utility tasks. ```sh # Clone and configure environment git clone https://github.com/kentcdodds/kentcdodds.com.git cd kentcdodds.com cp services/site/.env.example services/site/.env # Full setup (installs deps, migrates DB, validates, primes cache, installs Playwright, runs e2e) npm run setup -s # Start the development server (http://localhost:3000, all APIs mocked via MSW) npm run dev ``` ```sh # Development npm run dev # start dev server on :3000 with MOCKS=true npm run start # production mode (NODE_ENV=production) npm run start:mocks # production mode with mock APIs # Testing npm run test # unit + browser component tests (Vitest) npm run test:backend # Vitest backend tests only npm run test:browser # Vitest browser-mode tests (requires Playwright) npm run test:e2e:dev # Playwright e2e against dev server npm run test:e2e:run # Playwright e2e in headless CI mode (builds first) npm run test:e2e:install # install Playwright Chromium browser # Quality npm run lint # Oxlint npm run lint:all # Oxlint across all workspaces npm run typecheck # react-router typegen + tsc npm run typecheck:all # tsc across all workspaces npm run format # Prettier write npm run format:staged # Prettier on staged files (same as pre-commit) # Build npm run build # production build for the site npm run build:all # build all workspaces (used by pre-commit hook) # Database npm exec --workspace kentcdodds.com prisma migrate reset --force # ^ resets SQLite DB, applies migrations, runs seed script # Seed creates admin user: me@kentcdodds.com / iliketwix (role ADMIN, Blue Team) # Cache npm run prime-cache:mocks # pre-populates MDX cache by hitting the server once npm run prime-cache:prod # same but against the real production server # Workspace graph npm run nx:graph # open Nx dependency graph in browser ``` -------------------------------- ### Manual Project Setup Commands Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/CONTRIBUTING.md Commands to manually set up the project if the npm run setup script fails, including cloning, environment setup, dependency installation, database migration, validation, and cache priming. ```sh git clone cd ./kentcdodds.com # copy the site env example to services/site/.env # everything's mocked out during development so you shouldn't need to # change any of these values unless you want to hit real environments. cp services/site/.env.example services/site/.env # Install deps npm install # setup database npm exec --workspace kentcdodds.com prisma migrate reset --force # run build, typecheck, linting npm run validate # setup cache database npm run prime-cache:mocks # Install playwright browsers npm run test:e2e:install # run e2e tests npm run test:e2e:run ``` -------------------------------- ### Basic Web Worker Setup and Communication Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/speed-up-your-app-with-web-workers.mdx This example demonstrates the fundamental setup for using Web Workers. It shows how to create a worker from the main script, send messages to it, and receive messages back. Use this for offloading tasks to a background thread. ```html ``` ```javascript // main.js const worker = new Worker('worker.js') worker.postMessage('Hello Worker') worker.onmessage = (e) => { console.log('main.js: Message received from worker:', e.data) } // if you want to "uninstall" the web worker then use: // worker.terminate() ``` ```javascript // worker.js this.onmessage = (e) => { console.log('worker.js: Message received from main script', e.data) this.postMessage('Hello main') } ``` -------------------------------- ### Prisma Database Client and Example Queries Source: https://context7.com/kentcdodds/kentcdodds.com/llms.txt Singleton Prisma client setup and example queries for finding a user with their sessions and creating a new session. Uses SQLite via Prisma. ```ts // services/site/app/utils/prisma.server.ts — singleton Prisma client import { prisma } from '#app/utils/prisma.server.ts' // Example query — find a user with their sessions: const user = await prisma.user.findUnique({ where: { email: 'me@kentcdodds.com' }, select: { id: true, email: true, role: true, team: true, sessions: { select: { id: true, expirationDate: true } }, }, }) // Create a session (called by session.signIn()): const session = await prisma.session.create({ data: { userId: user.id, expirationDate: new Date(Date.now() + 1000 * 60 * 60 * 24 * 365), }, }) ``` -------------------------------- ### Run npm start Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/CONTRIBUTING.md Use this command to start the application. ```sh CMD ["npm", "start"] ``` -------------------------------- ### Copy Environment Variables Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/README.md Copy the example environment file to a new file before running setup. This is a common step for configuring applications with environment-specific settings. ```bash cp services/site/.env.example services/site/.env ``` -------------------------------- ### Integration Test Setup for Express Server Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/how-i-structure-express-apps.mdx Demonstrates how to set up an integration test for an Express server by starting the server before tests and closing it afterwards. ```javascript import { startServer } from '../start' let server, baseURL beforeAll(async () => { server = await startServer() baseURL = `http://localhost:${server.address().port}/api` }) afterAll(() => server.close()) // make requests to the baseURL ``` -------------------------------- ### Start Local Development Server Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/README.md Initiate the local development server to build and run the application locally. Access the site at http://localhost:3000 after starting. ```bash npm run dev ``` -------------------------------- ### Application Initialization Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/how-i-structure-express-apps.mdx Configures the logger and starts the server. It's recommended to abstract server starting logic into a function for easier testing. ```javascript import logger from 'loglevel' import { startServer } from './start' logger.setLevel('info') startServer() ``` -------------------------------- ### Basic React Setup with React.createElement Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-react.mdx Initial setup using React and ReactDOM with Babel to compile `React.createElement` calls. This version does not yet use JSX. ```html
``` -------------------------------- ### Add Start Script to package.json Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-remix.mdx Add a `start` script to your `package.json` to run the production server using `remix-serve`. This script points to the build directory. ```json { "scripts": { "build": "remix build", "dev": "remix dev", "start": "remix-serve ./build" }, "dependencies": { "@remix-run/react": "^1.6.5", "@remix-run/serve": "^1.6.5", "react": "^18.2.0", "react-dom": "^18.2.0" }, "devDependencies": { "@remix-run/dev": "^1.6.5" } } ``` -------------------------------- ### Start YouTube Indexer Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/other/nas/youtube/nas-youtube-indexer.md Execute the main script to start the YouTube indexer. All arguments are forwarded to the Node script. ```shell other/nas/youtube/start-youtube-indexer.sh ``` -------------------------------- ### Start Remix Production Server Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-remix.mdx Execute this command to launch your locally built Remix application in production mode. It will start the server and provide the local URL. ```bash npm start ``` -------------------------------- ### Making a GET Request with the Fetch Wrapper Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/replace-axios-with-a-simple-custom-fetch-wrapper.mdx Example of how to use the custom fetch client function to make a GET request and handle both successful responses and errors. ```javascript client(`books?query=${encodeURIComponent(query)}`).then( (data) => { console.log('here are the books', data.books) }, (error) => { console.error('oh no, an error happened', error) }, ) ``` -------------------------------- ### Start Indexer with Arguments Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/other/nas/youtube/nas-youtube-indexer.md Pass arguments to the Node script through the start script, such as specifying videos or a maximum count. ```shell other/nas/youtube/start-youtube-indexer.sh --videos dQw4w9WgXcQ ``` ```shell other/nas/youtube/start-youtube-indexer.sh --max-videos 10 ``` -------------------------------- ### Pure Module Example in JavaScript Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/pure-modules.mdx Demonstrates how to structure JavaScript modules to be pure, meaning their imports have no side effects. This setup allows for predictable initialization and avoids unexpected behavior. ```javascript // a.js import { init } from './b' init() console.log('ready') ``` ```javascript // b.js import { serverData, init as initC } from './c' export function init() { initC() if (!serverData.user) { // redirect to login location.assign('/login') } } ``` ```javascript // c.js export const serverData = {} export function init() { const el = document.getElementById('server-data') const json = el.textContent Object.assign(serverData, JSON.parse(json)) } ``` -------------------------------- ### Configure Jest Environment for MSW Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/stop-mocking-fetch.mdx Integrate MSW with Jest by adding setup code to your `setupFilesAfterEnv` configuration. This ensures the mock server is started before tests run and properly closed afterward. ```javascript // test/setup-env.js // add this to your setupFilesAfterEnv config in jest so it's imported for every test file import { server } from './server.js' beforeAll(() => server.listen()) // if you need to add a handler after calling setupServer for some specific test // this will remove that handler for the rest of them // (which is important for test isolation): afterEach(() => server.resetHandlers()) afterAll(() => server.close()) ``` -------------------------------- ### Starting and Stopping a Server in Tests Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/avoid-nesting-when-youre-testing/index.mdx Shows a common use case for `beforeAll` and `afterAll` hooks: starting a server before all tests run and closing it afterward to manage resources effectively. ```js let server beforeAll(async () => { server = await startServer() }) afterAll(() => server.close()) ``` -------------------------------- ### Install Node.js Version Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/docs/agents/project-context.md Ensures the correct Node.js version (24) is installed and set as the default using nvm. ```bash nvm install 24 && nvm alias default 24 ``` -------------------------------- ### Install Playwright Browsers Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/docs/agents/project-context.md Installs the necessary Playwright browsers for running browser and E2E tests. ```bash npm run test:e2e:install ``` -------------------------------- ### Install React Experimental Version Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/how-to-enable-react-concurrent-mode.mdx Install the experimental versions of React and ReactDOM to enable Concurrent Mode. This is necessary as Concurrent Mode is not yet available in stable releases. ```sh npm install react@experimental react-dom@experimental # or: yarn add react@experimental react-dom@experimental ``` -------------------------------- ### Install Remix Serve Package Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-remix.mdx Install the @remix-run/serve package to enable running your Remix app on a development server. This package is built on top of @remix-run/express and @remix-run/node. ```sh npm install @remix-run/serve ``` -------------------------------- ### Final Simplified React HTML Setup Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-react.mdx A concise HTML file setup for React, utilizing CDN links for React, ReactDOM, and Babel standalone, with JSX directly embedded in the script tag for rendering. ```html
``` -------------------------------- ### Install Custom Dev Tools Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/make-your-own-dev-tools.mdx Export an `install` function from your dev tools file. This function is responsible for setting up and rendering your custom UI. It's recommended to add dev tools UI to the page after the DOM is ready. ```javascript import * as React from 'react' function install() { function DevTools() { return
Hi from the DevTools
} // add dev tools UI to the page const devToolsRoot = document.createElement('div') document.body.appendChild(devToolsRoot) ReactDOM.render(, devToolsRoot) } export { install } ``` -------------------------------- ### Install Function Dependencies Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-firebase-functions.mdx Navigate to the functions directory and install project dependencies using npm. This command also generates a package-lock.json file. ```sh cd functions && npm install ``` -------------------------------- ### Start Firebase Emulators Locally Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-firebase-functions.mdx Starts the Firebase emulators, including the functions emulator, allowing you to test your functions locally before deploying them to production. This command also provides URLs for accessing the emulators. ```sh firebase emulators:start ``` -------------------------------- ### Setup and Blog Post Loading Tests Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/aha-testing/index.mdx This snippet demonstrates setting up mock request and response objects for testing API endpoints. It includes tests for loading blog posts, showing how to assert the expected JSON output and handle different user locations. ```javascript import * as blogPostController from '../blog-post' // load the application-wide mock for the database. jest.mock('../../lib/db') function setup(overrides = {}) { const req = { locale: { source: 'default', language: 'en', region: 'GB', }, user: { guid: '0336397b-e29d-4b63-b94d-7e68a6fa3747', isActive: false, picture: 'http://placehold.it/32x32', age: 30, name: { first: 'Francine', last: 'Oconnor', }, company: 'ACME', email: 'francine.oconnor@ac.me', latitude: 51.507351, longitude: -0.127758, favoriteFruit: 'banana', }, body: {}, cookies: {}, query: {}, params: { bucket: 'photography', }, header(name) { return { Authorization: 'Bearer TEST_TOKEN', }[name] }, ...overrides, } const res = { clearCookie: jest.fn(), cookie: jest.fn(), end: jest.fn(), locals: { content: {}, }, json: jest.fn(), send: jest.fn(), sendStatus: jest.fn(), set: jest.fn(), } const next = jest.fn() return { req, res, next } } test('lists blog posts for the logged in user', async () => { const { req, res, next } = setup() await blogPostController.loadBlogPosts(req, res, next) expect(res.json).toHaveBeenCalledTimes(1) expect(res.json).toHaveBeenCalledWith({ posts: expect.arrayContaining([ expect.objectContaining({ title: 'Test Post 1', subtitle: 'This is the subtitle of Test Post 1', body: 'The is the body of Test Post 1', }), ]), }) }) test('returns an empty list when there are no blog posts', async () => { const { req, res, next } = setup() req.user.latitude = 31.230416 req.user.longitude = 121.473701 await blogPostController.loadBlogPosts(req, res, next) expect(res.json).toHaveBeenCalledTimes(1) expect(res.json).toHaveBeenCalledWith({ posts: [], }) }) ``` -------------------------------- ### React Counter with Logger Component Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/optimize-react-re-renders.mdx This example demonstrates a Counter component that includes a Logger component. The Logger component logs when it renders. This setup is used to illustrate React's re-render optimization. ```tsx // play with this on codesandbox: https://codesandbox.io/s/react-codesandbox-o9e9f import * as React from 'react' import ReactDOM from 'react-dom' function Logger(props) { console.log(`${props.label} rendered`) return null // what is returned here is irrelevant... } function Counter(props) { const [count, setCount] = React.useState(0) const increment = () => setCount((c) => c + 1) return (
{props.logger}
) } ReactDOM.render( } />, document.getElementById('root'), ) ``` -------------------------------- ### Example: Cachified Credits Data Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/how-i-built-a-modern-website-in-2021.mdx Demonstrates how to use the `cachified` function to fetch and cache data from a YAML file for the `/credits` page. It specifies the cache, key, max age, and the function to get fresh data, including validation. ```typescript async function getPeople({ request, forceFresh, }: { request?: Request forceFresh?: boolean | string }) { const allPeople = await cachified({ cache: redisCache, key: 'content:data:credits.yml', request, forceFresh, maxAge: 1000 * 60 * 60 * 24 * 30, getFreshValue: async () => { const creditsString = await downloadFile('content/data/credits.yml') const rawCredits = YAML.parse(creditsString) if (!Array.isArray(rawCredits)) { console.error('Credits is not an array', rawCredits) throw new Error('Credits is not an array.') } return rawCredits.map(mapPerson).filter(typedBoolean) }, checkValue: (value: unknown) => Array.isArray(value), }) return allPeople } ``` -------------------------------- ### SQLite Cache Adapter for Cachified Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/i-migrated-from-a-postgres-cluster-to-distributed-sqlite-with-litefs.mdx Implements a SQLite cache adapter for the 'cachified' library. This code defines functions to get, set, and delete cache entries from a SQLite database using prepared statements. Ensure the 'cacheDb' connection is properly established and 'better-sqlite3' is installed. ```typescript const preparedGet = cacheDb.prepare( 'SELECT value, metadata FROM cache WHERE key = ?' ) const preparedSet = cacheDb.prepare( 'INSERT OR REPLACE INTO cache (key, value, metadata) VALUES (@key, @value, @metadata)' ) const preparedDelete = cacheDb.prepare('DELETE FROM cache WHERE key = ?') export const cache: CachifiedCache = { name: 'SQLite cache', get(key) { const result = preparedGet.get(key) if (!result) return null return { metadata: JSON.parse(result.metadata), value: JSON.parse(result.value), } }, set(key, { value, metadata }) { preparedSet.run({ key, value: JSON.stringify(value), metadata: JSON.stringify(metadata), }) }, delete(key) { preparedDelete.run(key) }, } ``` -------------------------------- ### Development Script Setup Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/how-i-structure-express-apps.mdx Sets up Babel to transpile JavaScript files on the fly during development and then requires the main application source. ```javascript require('@babel/register') require('./src') ``` -------------------------------- ### Run Node.js Server Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/how-i-built-a-modern-website-in-2021.mdx Standard command to start a Node.js server. ```bash node . ``` -------------------------------- ### Composable Setup Functions for Tests Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/avoid-nesting-when-youre-testing/index.mdx Use these composable setup functions to reduce duplication in tests. They help manage test state and can be combined to achieve complex setups without mutable variables. ```tsx import { render } from '@testing-library/react' import userEvent from '@testing-library/user-event' import * as React from 'react' import Login from '../login' // here we have a bunch of setup functions that compose together for our test cases // I only recommend doing this when you have a lot of tests that do the same thing. // I'm including it here only as an example. These tests don't necessitate this // much abstraction. Read more: https://kcd.im/aha-testing function setup() { const handleSubmit = jest.fn() const utils = render() const user = { username: 'michelle', password: 'smith' } const changeUsernameInput = (value) => userEvent.type(utils.getByLabelText(/username/i), value) const changePasswordInput = (value) => userEvent.type(utils.getByLabelText(/password/i), value) const clickSubmit = () => userEvent.click(utils.getByText(/submit/i)) return { ...utils, handleSubmit, user, changeUsernameInput, changePasswordInput, clickSubmit, } } function setupSuccessCase() { const utils = setup() utils.changeUsernameInput(utils.user.username) utils.changePasswordInput(utils.user.password) utils.clickSubmit() return utils } function setupWithNoPassword() { const utils = setup() utils.changeUsernameInput(utils.user.username) utils.clickSubmit() const errorMessage = utils.getByRole('alert') return { ...utils, errorMessage } } function setupWithNoUsername() { const utils = setup() utils.changePasswordInput(utils.user.password) utils.clickSubmit() const errorMessage = utils.getByRole('alert') return { ...utils, errorMessage } } test('calls onSubmit with the username and password', () => { const { handleSubmit, user } = setupSuccessCase() expect(handleSubmit).toHaveBeenCalledTimes(1) expect(handleSubmit).toHaveBeenCalledWith(user) }) test('shows an error message when submit is clicked and no username is provided', () => { const { handleSubmit, errorMessage } = setupWithNoUsername() expect(errorMessage).toHaveTextContent(/username is required/i) expect(handleSubmit).not.toHaveBeenCalled() }) test('shows an error message when password is not provided', () => { const { handleSubmit, errorMessage } = setupWithNoPassword() expect(errorMessage).toHaveTextContent(/password is required/i) expect(handleSubmit).not.toHaveBeenCalled() }) ``` -------------------------------- ### getPeople Example Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/how-i-built-a-modern-website-in-2021.mdx An example demonstrating how to use cachified to fetch and cache data for the /credits page. ```APIDOC ## getPeople Function Example ### Description This function demonstrates the practical usage of `cachified` to retrieve and cache YAML data representing people's information. It utilizes `redisCache` for storage and specifies a `maxAge` for the cache entries. ### Function Signature ```typescript async function getPeople({ request, forceFresh, }: { request?: Request forceFresh?: boolean | string }): Promise> ``` ### Usage ```typescript const allPeople = await cachified({ cache: redisCache, key: 'content:data:credits.yml', request, forceFresh, maxAge: 1000 * 60 * 60 * 24 * 30, // 30 days getFreshValue: async () => { const creditsString = await downloadFile('content/data/credits.yml') const rawCredits = YAML.parse(creditsString) if (!Array.isArray(rawCredits)) { console.error('Credits is not an array', rawCredits) throw new Error('Credits is not an array.') } return rawCredits.map(mapPerson).filter(typedBoolean) }, checkValue: (value: unknown) => Array.isArray(value), }) return allPeople ``` ### Parameters for `cachified` in this example: - **`cache`**: `redisCache` - The Redis cache instance. - **`key`**: `'content:data:credits.yml'` - The cache key for this data. - **`request`**: The `request` object passed to `getPeople`. - **`forceFresh`**: The `forceFresh` value passed to `getPeople`. - **`maxAge`**: `1000 * 60 * 60 * 24 * 30` - Sets the cache entry to expire after 30 days. - **`getFreshValue`**: An async function that downloads `content/data/credits.yml`, parses it as YAML, and maps the data to person objects. - **`checkValue`**: A function that ensures the retrieved value is an array. ``` -------------------------------- ### Example Polyfill URL with Version and User Agent Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/polyfill-as-needed-with-polyfill-service.mdx Demonstrates how to construct a polyfill URL that includes a version parameter for cache busting and a user agent parameter for specific polyfill delivery. This allows for aggressive caching. ```plaintext polyfill.js?v=2&ua=Mozilla%2F5.0%20(Windows%20NT%2011.0%3B%20WOW64%3B%20Trident%2F7.0%3B%20rv%3A11.0)%20like%20Gecko ``` -------------------------------- ### Remix Project Generation Prompts Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/the-beginner-s-guide-to-remix.mdx Example output of the `create-remix` command, showing the interactive prompts for setting up a new Remix application. ```sh R E M I X 💿 Welcome to Remix! Let's get you set up with a new project. ? Where would you like to create your app? remix-jokes ? Where do you want to deploy? Choose Remix if you're unsure, it's easy to change deployment targets. Remix App Server ? TypeScript or JavaScript? TypeScript ? Do you want me to run `npm install`? Yes 💿 Created local .npmrc with Remix Registry ``` -------------------------------- ### Build the Application Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/README.md Build the application for production. This command compiles and bundles the necessary assets for deployment. ```bash npm run build ``` -------------------------------- ### Install Remix and React Dependencies Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-remix.mdx Installs Remix development tools and core React packages using npm. ```sh npm install react react-dom npm install --save-dev @remix-run/dev ``` -------------------------------- ### Run Local Development Server Source: https://context7.com/kentcdodds/kentcdodds.com/llms.txt Starts the local development server for the search worker. Ensure you are in the correct workspace directory. ```bash npm run dev --workspace search-worker ``` -------------------------------- ### Create Remix Entry Point Files Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-remix.mdx Creates the necessary entry point files for a Remix application: `entry.client.jsx` and `entry.server.jsx`. These files are required for Remix to build. ```sh mkdir app touch app/entry.client.jsx touch app/entry.server.jsx ``` -------------------------------- ### Initial Test Structure Example Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/test-isolation-with-react.mdx An example of how tests might be structured without proper isolation, leading to dependencies between test cases. ```tsx const utils = render() test('test 1', () => { // use utils here }) test('test 2', () => { // use utils here too }) ``` -------------------------------- ### Start Express Server with Async/Await and Error Handling Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/how-i-structure-express-apps.mdx Sets up an Express server with async/await middleware support and a generic error handler. Includes logic to properly close the server and handle process exit signals. ```javascript import express from 'express' // this is all it takes to enable async/await for express middleware import 'express-async-errors' import logger from 'loglevel' // all the routes for my app are retrieved from the src/routes/index.js module import { getRoutes } from './routes' function startServer({ port = process.env.PORT } = {}) { const app = express() // I mount my entire app to the /api route (or you could just do "/" if you want) app.use('/api', getRoutes()) // add the generic error handler just in case errors are missed by middleware app.use(errorMiddleware) // I prefer dealing with promises. It makes testing easier, among other things. // So this block of code allows me to start the express app and resolve the // promise with the express server return new Promise((resolve) => { const server = app.listen(port, () => { logger.info(`Listening on port ${server.address().port}`) // this block of code turns `server.close` into a promise API const originalClose = server.close.bind(server) server.close = () => { return new Promise((resolveClose) => { originalClose(resolveClose) }) } // this ensures that we properly close the server when the program exists setupCloseOnExit(server) // resolve the whole promise with the express server resolve(server) }) }) } // here's our generic error handler for situations where we didn't handle // errors properly function errorMiddleware(error, req, res, next) { if (res.headersSent) { next(error) } else { logger.error(error) res.status(500) res.json({ message: error.message, // we only add a `stack` property in non-production environments ...(process.env.NODE_ENV === 'production' ? null : { stack: error.stack }), }) } } // ensures we close the server in the event of an error. function setupCloseOnExit(server) { // thank you stack overflow // https://stackoverflow.com/a/14032965/971592 aSync function exitHandler(options = {}) { await server .close() .then(() => { logger.info('Server successfully closed') }) .catch((e) => { logger.warn('Something went wrong closing the server', e.stack) }) if (options.exit) process.exit() } // do something when app is closing process.on('exit', exitHandler) // catches ctrl+c event process.on('SIGINT', exitHandler.bind(null, { exit: true })) // catches "kill pid" (for example: nodemon restart) process.on('SIGUSR1', exitHandler.bind(null, { exit: true })) process.on('SIGUSR2', exitHandler.bind(null, { exit: true })) // catches uncaught exceptions process.on('uncaughtException', exitHandler.bind(null, { exit: true })) } export { startServer } ``` -------------------------------- ### Install Remix React Package Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-remix.mdx Installs the necessary `@remix-run/react` package to resolve build errors related to missing Remix components. ```sh npm install @remix-run/react ``` -------------------------------- ### Import User Profile Example Component Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/avoid-the-test-user/index.mdx Imports a React component for demonstration purposes. Ensure the component is correctly located at './user-profile-example'. ```javascript import UserProfileExample from './user-profile-example' ``` -------------------------------- ### Serve local files for module loading Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-es-modules-in-the-browser.mdx This command starts a local development server using npx serve. It is required to serve HTML and JavaScript files when working with ES Modules in the browser. ```bash npx serve ``` -------------------------------- ### Run Node.js Server with MSW Mocks Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/how-i-built-a-modern-website-in-2021.mdx Command to start a Node.js server with MSW mocks enabled by requiring a local mocks file. ```bash node --require ./mocks . ``` -------------------------------- ### Basic JavaScript Test Example Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/but-really-what-is-a-javascript-test.mdx A fundamental example of a JavaScript test that throws an error if an actual value does not match an expected value. This can be run using Node.js. ```javascript // basic-test.js const actual = true const expected = false if (actual !== expected) { throw new Error(`${actual} is not ${expected}`) } ``` -------------------------------- ### Set up MSW Server for Node.js Testing Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/stop-mocking-fetch.mdx Configure the MSW server for Node.js environments using `setupServer`. This allows you to intercept requests during your tests by providing the defined handlers. ```javascript // test/server.js import { rest } from 'msw' import { setupServer } from 'msw/node' import { handlers } from './server-handlers' const server = setupServer(...handlers) export { server, rest } ``` -------------------------------- ### Install Firebase CLI Tools Globally Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/super-simple-start-to-firebase-functions.mdx Installs the `firebase-tools` package globally using npm, which provides the `firebase` command-line interface for managing Firebase projects. ```sh npm install --global firebase-tools ``` -------------------------------- ### Accordion Component Example Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/testing-implementation-details.mdx A simple React class component demonstrating an accordion with state management for the open index. This component is used as an example for testing implementation details. ```tsx // accordion.js import * as React from 'react' import AccordionContents from './accordion-contents' class Accordion extends React.Component { state = { openIndex: 0 } setOpenIndex = (openIndex) => this.setState({ openIndex }) render() { const { openIndex } = this.state return (
{this.props.items.map((item, index) => ( <> {index === openIndex ? ( {item.contents} ) : null} ))}
) } } export default Accordion ``` -------------------------------- ### Listify Array Usage Examples Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/listify-a-java-script-array.mdx Demonstrates how to use the `listify` function with default and custom conjunctions. ```javascript const to = `To: ${listify(mentionedMembersNicknames)}` ``` ```javascript const didYouMean = `Did you mean ${listify(closeMatches, { conjunction: 'or ', })}?` ``` -------------------------------- ### Compiled Output from codegen.macro Examples Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/define-function-overload-types-with-type-script.mdx Presents the compiled JavaScript code resulting from the various codegen.macro usage examples, including generated constants, file lists, and JSX. ```javascript // using as a tagged template literal: const tag = 'this is an example' // using as a function const fn = 'this is another example' // codegen-ing an external module (and pass an argument): const jpgs = ['kody.jpg', 'olivia.jpg', 'marty.jpg'] const ui =
This is some example JSX code
``` -------------------------------- ### Styled-components Example Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/introducing-glamorous.mdx This demonstrates how to write a styled component using the styled-components library. It allows for CSS to be written directly within JavaScript. ```js const MyStyledDiv = styled.div` font-size: 20px; text-align: center; ` ``` -------------------------------- ### Shiki Highlighter Worker Setup Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/fixing-a-memory-leak-in-a-production-node-js-app.mdx Sets up the Shiki highlighter within a worker script for on-demand compilation. Ensure themes are loaded and the highlighter is initialized. ```javascript const path = require('path') const { getHighlighter, loadTheme } = require('shiki') const themeName = 'base16' let theme, highlighter module.exports = async function highlight({ code, language }) { theme = theme || (await loadTheme(path.resolve(__dirname, 'base16.json'))) highlighter = highlighter || (await getHighlighter({ themes: [theme] })) const fgColor = convertFakeHexToCustomProp( highlighter.getForegroundColor(themeName) || '', ) const bgColor = convertFakeHexToCustomProp( highlighter.getBackgroundColor(themeName) || '', ) the tokens = highlighter.codeToThemedTokens(code, language, themeName) return { fgColor, bgColor, tokens: tokens.map((lineTokens) => lineTokens.map((t) => ({ content: t.content, color: t.color })) ), } } // The theme actually stores #FFFF${base-16-color-id} because vscode-textmate // requires colors to be valid hex codes, if they aren't, it changes them to a // default, so this is a mega hack to trick it. function convertFakeHexToCustomProp(color) { return color.replace(/^#FFFF(.+)/, 'var(--base$1)') } ``` -------------------------------- ### Example of Stale Closure Bug with useState Source: https://github.com/kentcdodds/kentcdodds.com/blob/main/services/site/content/blog/should-i-usestate-or-usereducer.mdx This example demonstrates a stale closure bug that can occur with useState when multiple effects update the same state without proper dependency management. ```tsx function Example() { const [state, { set }] = useUndo('first') React.useEffect(() => { set('second') }, []) React.useEffect(() => { set('third') }, []) return
{JSON.stringify(state, null, 2)}
} ```