diff options
Diffstat (limited to 'docs/dev')
-rw-r--r-- | docs/dev/bundev.md | 11 | ||||
-rw-r--r-- | docs/dev/cra.md | 31 | ||||
-rw-r--r-- | docs/dev/css.md | 77 | ||||
-rw-r--r-- | docs/dev/discord.md | 26 | ||||
-rw-r--r-- | docs/dev/frameworks.md | 151 | ||||
-rw-r--r-- | docs/dev/nextjs.md | 33 |
6 files changed, 329 insertions, 0 deletions
diff --git a/docs/dev/bundev.md b/docs/dev/bundev.md new file mode 100644 index 000000000..baccf7658 --- /dev/null +++ b/docs/dev/bundev.md @@ -0,0 +1,11 @@ +- pages +- auto-bundle dependencies +- pages is function that returns a list of pages? +- plugins for svelte and vue +- custom loaders +- HMR +- server endpoints + +```ts +Bun.serve({}); +``` diff --git a/docs/dev/cra.md b/docs/dev/cra.md new file mode 100644 index 000000000..8eb868715 --- /dev/null +++ b/docs/dev/cra.md @@ -0,0 +1,31 @@ +To create a new React app: + +```bash +$ bun create react ./app +$ cd app +$ bun dev # start dev server +``` + +To use an existing React app: + +```bash +$ bun add -d react-refresh # install React Fast Refresh +$ bun bun ./src/index.js # generate a bundle for your entry point(s) +$ bun dev # start the dev server +``` + +From there, Bun relies on the filesystem for mapping dev server paths to source files. All URL paths are relative to the project root (where `package.json` is located). + +Here are examples of routing source code file paths: + +| Dev Server URL | File Path (relative to cwd) | +| -------------------------- | --------------------------- | +| /src/components/Button.tsx | src/components/Button.tsx | +| /src/index.tsx | src/index.tsx | +| /pages/index.js | pages/index.js | + +You do not need to include file extensions in `import` paths. CommonJS-style import paths without the file extension work. + +You can override the public directory by passing `--public-dir="path-to-folder"`. + +If no directory is specified and `./public/` doesn’t exist, Bun will try `./static/`. If `./static/` does not exist, but won’t serve from a public directory. If you pass `--public-dir=./` Bun will serve from the current directory, but it will check the current directory last instead of first. diff --git a/docs/dev/css.md b/docs/dev/css.md new file mode 100644 index 000000000..a74f5d1ea --- /dev/null +++ b/docs/dev/css.md @@ -0,0 +1,77 @@ +## With `bun dev` + +When importing CSS in JavaScript-like loaders, CSS is treated special. + +By default, Bun will transform a statement like this: + +```js +import "../styles/global.css"; +``` + +### When `platform` is `browser` + +```js +globalThis.document?.dispatchEvent( + new CustomEvent("onimportcss", { + detail: "http://localhost:3000/styles/globals.css", + }), +); +``` + +An event handler for turning that into a `<link>` is automatically registered when HMR is enabled. That event handler can be turned off either in a framework’s `package.json` or by setting `globalThis["Bun_disableCSSImports"] = true;` in client-side code. Additionally, you can get a list of every .css file imported this way via `globalThis["__BUN"].allImportedStyles`. + +### When `platform` is `bun` + +```js +//@import url("http://localhost:3000/styles/globals.css"); +``` + +Additionally, Bun exposes an API for SSR/SSG that returns a flat list of URLs to css files imported. That function is `Bun.getImportedStyles()`. + +```ts +// This specifically is for "framework" in package.json when loaded via `bun dev` +// This API needs to be changed somewhat to work more generally with Bun.js +// Initially, you could only use Bun.js through `bun dev` +// and this API was created at that time +addEventListener("fetch", async (event: FetchEvent) => { + let route = Bun.match(event); + const App = await import("pages/_app"); + + // This returns all .css files that were imported in the line above. + // It’s recursive, so any file that imports a CSS file will be included. + const appStylesheets = bun.getImportedStyles(); + + // ...rest of code +}); +``` + +This is useful for preventing flash of unstyled content. + +## With `bun bun` + +Bun bundles `.css` files imported via `@import` into a single file. It doesn’t autoprefix or minify CSS today. Multiple `.css` files imported in one JavaScript file will _not_ be bundled into one file. You’ll have to import those from a `.css` file. + +This input: + +```css +@import url("./hi.css"); +@import url("./hello.css"); +@import url("./yo.css"); +``` + +Becomes: + +```css +/* hi.css */ +/* ...contents of hi.css */ +/* hello.css */ +/* ...contents of hello.css */ +/* yo.css */ +/* ...contents of yo.css */ +``` + +## CSS runtime + +To support hot CSS reloading, Bun inserts `@supports` annotations into CSS that tag which files a stylesheet is composed of. Browsers ignore this, so it doesn’t impact styles. + +By default, Bun’s runtime code automatically listens to `onimportcss` and will insert the `event.detail` into a `<link rel="stylesheet" href={${event.detail}}>` if there is no existing `link` tag with that stylesheet. That’s how Bun’s equivalent of `style-loader` works. diff --git a/docs/dev/discord.md b/docs/dev/discord.md new file mode 100644 index 000000000..d3e9c5a2b --- /dev/null +++ b/docs/dev/discord.md @@ -0,0 +1,26 @@ +## Creating a Discord bot with Bun + +Discord bots perform actions in response to _application commands_. There are 3 types of commands accessible in different interfaces: the chat input, a message's context menu (top-right menu or right-clicking in a message), and a user's context menu (right-clicking on a user). + +To get started you can use the interactions template: + +```bash +bun create discord-interactions my-interactions-bot +cd my-interactions-bot +``` + +If you don't have a Discord bot/application yet, you can create one [here (https://discord.com/developers/applications/me)](https://discord.com/developers/applications/me). + +Invite bot to your server by visiting `https://discord.com/api/oauth2/authorize?client_id=<your_application_id>&scope=bot%20applications.commands` + +Afterwards you will need to get your bot's token, public key, and application id from the application page and put them into `.env.example` file + +Then you can run the http server that will handle your interactions: + +```bash +$ bun install +$ mv .env.example .env +$ bun run.js # listening on port 1337 +``` + +Discord does not accept an insecure HTTP server, so you will need to provide an SSL certificate or put the interactions server behind a secure reverse proxy. For development, you can use ngrok/cloudflare tunnel to expose local ports as secure URL. diff --git a/docs/dev/frameworks.md b/docs/dev/frameworks.md new file mode 100644 index 000000000..9af7fc45b --- /dev/null +++ b/docs/dev/frameworks.md @@ -0,0 +1,151 @@ +{% callout %} +**Warning** — This will soon have breaking changes. It was designed when Bun was mostly a dev server and not a JavaScript runtime. +{% /callout %} + +Frameworks preconfigure Bun to enable developers to use Bun with their existing tooling. + +Frameworks are configured via the `framework` object in the `package.json` of the framework (not in the application’s `package.json`): + +Here is an example: + +```json +{ + "name": "bun-framework-next", + "version": "0.0.0-18", + "description": "", + "framework": { + "displayName": "Next.js", + "static": "public", + "assetPrefix": "_next/", + "router": { + "dir": ["pages", "src/pages"], + "extensions": [".js", ".ts", ".tsx", ".jsx"] + }, + "css": "onimportcss", + "development": { + "client": "client.development.tsx", + "fallback": "fallback.development.tsx", + "server": "server.development.tsx", + "css": "onimportcss", + "define": { + "client": { + ".env": "NEXT_PUBLIC_", + "defaults": { + "process.env.__NEXT_TRAILING_SLASH": "false", + "process.env.NODE_ENV": "\"development\"", + "process.env.__NEXT_ROUTER_BASEPATH": "''", + "process.env.__NEXT_SCROLL_RESTORATION": "false", + "process.env.__NEXT_I18N_SUPPORT": "false", + "process.env.__NEXT_HAS_REWRITES": "false", + "process.env.__NEXT_ANALYTICS_ID": "null", + "process.env.__NEXT_OPTIMIZE_CSS": "false", + "process.env.__NEXT_CROSS_ORIGIN": "''", + "process.env.__NEXT_STRICT_MODE": "false", + "process.env.__NEXT_IMAGE_OPTS": "null" + } + }, + "server": { + ".env": "NEXT_", + "defaults": { + "process.env.__NEXT_TRAILING_SLASH": "false", + "process.env.__NEXT_OPTIMIZE_FONTS": "false", + "process.env.NODE_ENV": "\"development\"", + "process.env.__NEXT_OPTIMIZE_IMAGES": "false", + "process.env.__NEXT_OPTIMIZE_CSS": "false", + "process.env.__NEXT_ROUTER_BASEPATH": "''", + "process.env.__NEXT_SCROLL_RESTORATION": "false", + "process.env.__NEXT_I18N_SUPPORT": "false", + "process.env.__NEXT_HAS_REWRITES": "false", + "process.env.__NEXT_ANALYTICS_ID": "null", + "process.env.__NEXT_CROSS_ORIGIN": "''", + "process.env.__NEXT_STRICT_MODE": "false", + "process.env.__NEXT_IMAGE_OPTS": "null", + "global": "globalThis", + "window": "undefined" + } + } + } + } + } +} +``` + +Here are type definitions: + +```ts +type Framework = Environment & { + // This changes what’s printed in the console on load + displayName?: string; + + // This allows a prefix to be added (and ignored) to requests. + // Useful for integrating an existing framework that expects internal routes to have a prefix + // e.g. "_next" + assetPrefix?: string; + + development?: Environment; + production?: Environment; + + // The directory used for serving unmodified assets like fonts and images + // Defaults to "public" if exists, else "static", else disabled. + static?: string; + + // "onimportcss" disables the automatic "onimportcss" feature + // If the framework does routing, you may want to handle CSS manually + // "facade" removes CSS imports from JavaScript files, + // and replaces an imported object with a proxy that mimics CSS module support without doing any class renaming. + css?: "onimportcss" | "facade"; + + // Bun's filesystem router + router?: Router; +}; + +type Define = { + // By passing ".env", Bun will automatically load .env.local, .env.development, and .env if exists in the project root + // (in addition to the processes’ environment variables) + // When "*", all environment variables will be automatically injected into the JavaScript loader + // When a string like "NEXT_PUBLIC_", only environment variables starting with that prefix will be injected + + ".env": string | "*"; + + // These environment variables will be injected into the JavaScript loader + // These are the equivalent of Webpack’s resolve.alias and esbuild’s --define. + // Values are parsed as JSON, so they must be valid JSON. The only exception is '' is a valid string, to simplify writing stringified JSON in JSON. + // If not set, `process.env.NODE_ENV` will be transformed into "development". + "defaults": Record<string, string>; +}; + +type Environment = { + // This is a wrapper for the client-side entry point for a route. + // This allows frameworks to run initialization code on pages. + client: string; + // This is a wrapper for the server-side entry point for a route. + // This allows frameworks to run initialization code on pages. + server: string; + // This runs when "server" code fails to load due to an exception. + fallback: string; + + // This is how environment variables and .env is configured. + define?: Define; +}; + +// Bun's filesystem router +// Currently, Bun supports pages by either an absolute match or a parameter match. +// pages/index.tsx will be executed on navigation to "/" and "/index" +// pages/posts/[id].tsx will be executed on navigation to "/posts/123" +// Routes & parameters are automatically passed to `fallback` and `server`. +type Router = { + // This determines the folder to look for pages + dir: string[]; + + // These are the allowed file extensions for pages. + extensions?: string[]; +}; +``` + +To use a framework, you pass `bun bun --use package-name`. + +Your framework’s `package.json` `name` should start with `bun-framework-`. This is so that people can type something like `bun bun --use next` and it will check `bun-framework-next` first. This is similar to how Babel plugins tend to start with `babel-plugin-`. + +For developing frameworks, you can also do `bun bun --use ./relative-path-to-framework`. + +If you’re interested in adding a framework integration, please reach out. There’s a lot here, and it’s not entirely documented yet. diff --git a/docs/dev/nextjs.md b/docs/dev/nextjs.md new file mode 100644 index 000000000..92849c989 --- /dev/null +++ b/docs/dev/nextjs.md @@ -0,0 +1,33 @@ +To create a new Next.js app with bun: + +```bash +$ bun create next ./app +$ cd app +$ bun dev # start dev server +``` + +To use an existing Next.js app with bun: + +```bash +$ bun add bun-framework-next +$ echo "framework = 'next'" > bunfig.toml +$ bun bun # bundle dependencies +$ bun dev # start dev server +``` + +Many of Next.js’ features are supported, but not all. + +Here’s what doesn’t work yet: + +- `getStaticPaths` +- same-origin `fetch` inside of `getStaticProps` or `getServerSideProps` +- locales, zones, `assetPrefix` (workaround: change `--origin \"http://localhost:3000/assetPrefixInhere\"`) +- `next/image` is polyfilled to a regular `<img src>` tag. +- `proxy` and anything else in `next.config.js` +- API routes, middleware (middleware is easier to support, though! Similar SSR API) +- styled-jsx (technically not Next.js, but often used with it) +- React Server Components + +When using Next.js, Bun automatically reads configuration from `.env.local`, `.env.development` and `.env` (in that order). `process.env.NEXT_PUBLIC_` and `process.env.NEXT_` automatically are replaced via `--define`. + +Currently, any time you import new dependencies from `node_modules`, you will need to re-run `bun bun --use next`. This will eventually be automatic. |