Skip to content

Commit

Permalink
Expose JSX compilation to renderers (#588)
Browse files Browse the repository at this point in the history
* feat: add support for `jsxImportSource`, new JSX transform

* Renderer: add Solid renderer (#667)

* feat: add support for `jsxImportSource`, new JSX transform

* WIP: solid renderer

* [Renderer] Solid (#656)

* feat: add support for `jsxImportSource`, new JSX transform

* WIP: solid renderer

* Solid renderer: fix SSR of children, hydration (top level)

Caveat: cannot hydrate children/descendants of hydrated parents

* Fix hydration of fragments

* fix: SyntaxError in React/Preact renderers

* fix: errors in React/Preact renderers

* feat: update react external

* chore: update examples

* chore: delete old changelog

* chore: update astro config

Co-authored-by: Nate Moore <nate@skypack.dev>

* Changing the preact to Solid (#669)

* chore: use new client:visible syntax

* fix: dev script issue

* chore: cleanup SolidJS example

* docs: update framework example docs

* chore: cleanup framework-multiple example

* fix: remove SolidJS false-positives from Preact renderer

* chore: add changeset

Co-authored-by: eyelidlessness <eyelidlessness@users.noreply.github.com>
Co-authored-by: Abdullah Mzaien <s201540830@kfupm.edu.sa>

* feat(create-astro): add Solid support

* docs: add JSX options to renderer reference

* chore: add changeset for P/React renderers

* fix: move react/server.js to external

* chore: remove brewfile

* Revert "feat: add support for `jsxImportSource`, new JSX transform"

This reverts commit 077c4bf.

* fix: remove `react-dom/server` from `external`

* chore: remove unused dependency

* feat: improve JSX error messages

* Revert "Revert "feat: add support for `jsxImportSource`, new JSX transform""

This reverts commit f6c2896.

* docs: update jsxImportSource

* feat: improve error message

* feat: improve error logging for JSX renderers

* tests: add jsx-runtime tests

* chore: update snowpack

Co-authored-by: eyelidlessness <eyelidlessness@users.noreply.github.com>
Co-authored-by: Abdullah Mzaien <s201540830@kfupm.edu.sa>
  • Loading branch information
3 people authored and FredKSchott committed Jul 22, 2021
1 parent 5ec97e6 commit b0157a5
Show file tree
Hide file tree
Showing 46 changed files with 2,943 additions and 2,415 deletions.
5 changes: 5 additions & 0 deletions .changeset/dull-queens-melt.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/renderer-solid': minor
---

Initial release
10 changes: 10 additions & 0 deletions .changeset/fair-cats-count.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@astrojs/renderer-preact': minor
'@astrojs/renderer-react': minor
---

Switches to [the new JSX Transform](https://reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html) originally introduced for React v17. This also leverages the new `jsxTransformOptions` options for renderers.

This change also removes the need for importing your Framework's `jsxFactory` directly, which means you can wave goodbye to `import React from "react";` and `import { h } from "preact";`.

> **If you are using mutliple frameworks** and a file doesn't reference `react` or `preact`, Astro might not be able to locate the correct renderer! You can add a pragma comment like `/** @jsxImportSource preact */` to the top of your file. Alternatively, just import the JSX pragma as you traditionally would have.
5 changes: 5 additions & 0 deletions .changeset/five-bobcats-joke.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'create-astro': patch
---

Add support for [Solid](https://www.solidjs.com/)
5 changes: 5 additions & 0 deletions .changeset/lemon-yaks-dream.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@astrojs/renderer-preact': patch
---

Update `check` logic to exclude false-positives from SolidJS
45 changes: 45 additions & 0 deletions docs/src/pages/reference/renderer-reference.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,54 @@ export default {
external: ['dep'] // optional, dependencies that should not be built by snowpack
polyfills: ['./shadow-dom-polyfill.js'] // optional, module scripts that should be loaded before client hydration.
hydrationPolyfills: ['./hydrate-framework.js'] // optional, polyfills that need to run before hydration ever occurs.
jsxImportSource: 'preact', // optional, the name of the library from which JSX is imported
jsxTransformOptions: async () => { // optional, a function to transform JSX files
const { default: { default: jsx }} = await import('@babel/plugin-transform-react-jsx');
return {
plugins: [
jsx({}, { runtime: 'automatic', importSource: 'preact' })
]
}
}
};
```

### JSX Support

Astro is unique in that it allows you to mix multiple types of JSX/TSX files in a single project. It does this by reading the `jsxImportSource` and `jsxTransformOptions` from renderers and transforming a file with [Babel](https://babeljs.io/).

#### `jsxImportSource`
This is the name of your library (for example `preact` or `react` or `solid-js`) which, if encountered in a file, will signal to Astro that this renderer should be used.

Users may also manually define `/** @jsxImportSource preact */` in to ensure that the file is processed by this renderer (if, for example, the file has no imports).

#### `jsxTransformOptions`
This is an `async` function that returns information about how to transform matching JSX files with [Babel](https://babeljs.io/). It supports [`plugins`](https://babeljs.io/docs/en/plugins) or [`presets`](https://babeljs.io/docs/en/presets) to be passed directly to Babel.

> Keep in mind that this transform doesn't need to handle TSX separately from JSX, Astro handles that for you!
The arguments passed to `jsxTransformOptions` follow Snowpack's `load()` plugin hook. These allow you to pass separate Babel configurations for various conditions, like if your files should be compiled differently in SSR mode.

```ts
export interface JSXTransformOptions {
(context: {
/** True if builder is in dev mode (`astro dev`) */
isDev: boolean;
/** True if HMR is enabled (add any HMR code to the output here). */
isHmrEnabled: boolean;
/** True if builder is in SSR mode */
isSSR: boolean;
/** True if file being transformed is inside of a package. */
isPackage: boolean;
}) => {
plugins?: any[];
presets?: any[];
}
}
```

####

### Server Entrypoint (`server.js`)

The server entrypoint of a renderer is responsible for checking if a component should use this renderer, and if so, how that component should be rendered to a string of static HTML.
Expand Down
2 changes: 0 additions & 2 deletions examples/framework-multiple/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,3 @@ npm init astro -- --template framework-multiple
This example showcases Astro's built-in support for multiple frameworks ([React](https://reactjs.org), [Preact](https://preactjs.com), [Svelte](https://svelte.dev), and [Vue (`v3.x`)](https://v3.vuejs.org/)).

No configuration is needed to enable these frameworks—just start writing components in `src/components`.

> **Note**: If used, components _must_ include a JSX factory (ex. `import React from "react"`, `import { h } from "preact"`). Astro is unable to determine which framework is used without having the [JSX factory](https://mariusschulz.com/blog/per-file-jsx-factories-in-typescript#what-is-a-jsx-factory) in scope.
8 changes: 7 additions & 1 deletion examples/framework-multiple/astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,11 @@ export default {
// port: 3000, // The port to run the dev server on.
// tailwindConfig: '', // Path to tailwind.config.js if used, e.g. './tailwind.config.js'
},
renderers: ['@astrojs/renderer-preact', '@astrojs/renderer-react', '@astrojs/renderer-svelte', '@astrojs/renderer-vue'],
renderers: [
'@astrojs/renderer-preact',
'@astrojs/renderer-react',
'@astrojs/renderer-svelte',
'@astrojs/renderer-vue',
'@astrojs/renderer-solid',
]
};
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { h, Fragment } from 'preact';
import { useState } from 'preact/hooks';

/** a counter written in Preact */
Expand Down
12 changes: 12 additions & 0 deletions examples/framework-multiple/src/components/PreactSFC.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/** @jsxImportSource preact */

/** a counter written in Preact */
export default function PreactSFC({ children }) {
return (
<>
<div className="counter">
Hello from Preact!
</div>
</>
);
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState } from 'react';
import { useState } from 'react';

/** a counter written in React */
export function Counter({ children }) {
Expand Down
21 changes: 21 additions & 0 deletions examples/framework-multiple/src/components/SolidCounter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createSignal } from "solid-js";

/** a counter written with Solid */
export default function SolidCounter({ children }) {
const [count, setCount] = createSignal(0);
const add = () => setCount(count() + 1);
const subtract = () => setCount(count() - 1);

return (
<>
<div id="solid" class="counter">
<button onClick={subtract}>-</button>
<pre>{count()}</pre>
<button onClick={add}>+</button>
</div>
<div class="children">
{children}
</div>
</>
);
}
7 changes: 6 additions & 1 deletion examples/framework-multiple/src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
import { A, B as Renamed } from '../components';
import * as react from '../components/ReactCounter.jsx';
import { PreactCounter } from '../components/PreactCounter.tsx';
import PreactSFC from '../components/PreactSFC.tsx';
import SolidCounter from '../components/SolidCounter.tsx';
import VueCounter from '../components/VueCounter.vue';
import SvelteCounter from '../components/SvelteCounter.svelte';
// Full Astro Component Syntax:
// https://docs.astro.build/core-concepts/astro-components/
---
Expand Down Expand Up @@ -45,6 +46,10 @@ import SvelteCounter from '../components/SvelteCounter.svelte';
<h1>Hello Preact!</h1>
</PreactCounter>

<SolidCounter client:visible>
<h1>Hello Solid!</h1>
</SolidCounter>

<VueCounter client:visible>
<h1>Hello Vue!</h1>
</VueCounter>
Expand Down
35 changes: 31 additions & 4 deletions examples/framework-preact/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
# Using Preact with Astro

```
This example showcases Astro's built-in support for [Preact](https://www.preactjs.com/).

## Installation

### Automatic

Bootstrap your Astro project with this template!

```shell
npm init astro -- --template framework-preact
```

This example showcases Astro's built-in support for [Preact](https://preactjs.com/).
### Manual

To use Preact components in your Astro project:

1. Install `@astrojs/renderer-preact`

```shell
npm i @astrojs/renderer-preact
```

2. Add `"@astrojs/renderer-preact"` to your `renderers` in `astro.config.mjs`.

```js
export default {
renderers: [
"@astrojs/renderer-preact",
// optionally, others...
]
}
```

No configuration is needed to enable Preact support—just start writing Preact components in `src/components`.
## Usage

> **Note**: If used, components _must_ include the JSX factory (ex. `import { h } from "preact"`). Astro is unable to determine which framework is used without having the [JSX factory](https://mariusschulz.com/blog/per-file-jsx-factories-in-typescript#what-is-a-jsx-factory) in scope.
Write your Preact components as `.jsx` or `.tsx` files in your project.
35 changes: 31 additions & 4 deletions examples/framework-react/README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
# Using React with Astro

```
This example showcases Astro's built-in support for [React](https://reactjs.org/).

## Installation

### Automatic

Bootstrap your Astro project with this template!

```shell
npm init astro -- --template framework-react
```

This example showcases Astro's built-in support for [React](https://reactjs.org/).
### Manual

To use React components in your Astro project:

1. Install `@astrojs/renderer-react`

```shell
npm i @astrojs/renderer-react
```

2. Add `"@astrojs/renderer-react"` to your `renderers` in `astro.config.mjs`.

```js
export default {
renderers: [
"@astrojs/renderer-react",
// optionally, others...
]
}
```

No configuration is needed to enable React support—just start writing React components in `src/components`.
## Usage

> **Note**: If used, components _must_ include the JSX factory (ex. `import React from "react"`). Astro is unable to determine which framework is used without having the [JSX factory](https://mariusschulz.com/blog/per-file-jsx-factories-in-typescript#what-is-a-jsx-factory) in scope.
Write your React components as `.jsx` or `.tsx` files in your project.
18 changes: 18 additions & 0 deletions examples/framework-solid/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# build output
dist

# dependencies
node_modules/
.snowpack/

# logs
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# environment variables
.env
.env.production

# macOS-specific files
.DS_Store
2 changes: 2 additions & 0 deletions examples/framework-solid/.npmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
## force pnpm to hoist
shamefully-hoist = true
38 changes: 38 additions & 0 deletions examples/framework-solid/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
# Using Solid with Astro

This example showcases Astro's built-in support for [Solid](https://www.solidjs.com/).

## Installation

### Automatic

Bootstrap your Astro project with this template!

```shell
npm init astro --template framework-solid
```

### Manual

To use Solid components in your Astro project:

1. Install `@astrojs/renderer-solid`

```shell
npm i @astrojs/renderer-solid
```

2. Add `"@astrojs/renderer-solid"` to your `renderers` in `astro.config.mjs`.

```js
export default {
renderers: [
"@astrojs/renderer-solid",
// optionally, others...
]
}
```

## Usage

Write your Solid components as `.jsx` or `.tsx` files in your project.
17 changes: 17 additions & 0 deletions examples/framework-solid/astro.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export default {
// projectRoot: '.', // Where to resolve all URLs relative to. Useful if you have a monorepo project.
// pages: './src/pages', // Path to Astro components, pages, and data
// dist: './dist', // When running `astro build`, path to final static output
// public: './public', // A folder of static files Astro will copy to the root. Useful for favicons, images, and other files that don’t need processing.
buildOptions: {
// site: 'http://example.com', // Your public domain, e.g.: https://my-site.dev/. Used to generate sitemaps and canonical URLs.
// sitemap: true, // Generate sitemap (set to "false" to disable)
},
devOptions: {
// port: 3000, // The port to run the dev server on.
// tailwindConfig: '', // Path to tailwind.config.js if used, e.g. './tailwind.config.js'
},
renderers: [
'@astrojs/renderer-solid'
]
};
16 changes: 16 additions & 0 deletions examples/framework-solid/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "@example/framework-solid",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "astro dev",
"build": "astro build"
},
"devDependencies": {
"astro": "^0.18.0-next.1",
"@astrojs/renderer-solid": "0.0.1"
},
"snowpack": {
"workspaceRoot": "../.."
}
}
21 changes: 21 additions & 0 deletions examples/framework-solid/src/components/Counter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { createSignal } from "solid-js";

/** */
export default function SolidCounter({ children }) {
const [count, setCount] = createSignal(0);
const add = () => setCount(count() + 1);
const subtract = () => setCount(count() - 1);

return (
<>
<div class="counter">
<button onClick={subtract}>-</button>
<pre>{count()}</pre>
<button onClick={add}>+</button>
</div>
<div class="children">
{children}
</div>
</>
);
}
Loading

0 comments on commit b0157a5

Please sign in to comment.