Compare commits

..

No commits in common. "main" and "v0.3.1" have entirely different histories.
main ... v0.3.1

10 changed files with 5884 additions and 3523 deletions

View file

@ -1,11 +0,0 @@
image: alpine/edge
secrets:
- bbfcb6dc-7c4a-42ee-a11a-022f0339a133
environment:
REPO: astro-resume
GH_USER: ayoayco
tasks:
- push-mirror: |
cd ~/"${REPO}"
git config --global credential.helper store
git push --mirror "https://github.com/${GH_USER}/${REPO}"

118
README.md
View file

@ -1,18 +1,13 @@
> [!NOTE]
> This project moved to [SourceHut](https://git.sr.ht/~ayoayco/astro-resume).
# Astro Resume # Astro Resume
[![Package information: NPM version](https://img.shields.io/npm/v/@ayco/astro-resume)](https://www.npmjs.com/package/@ayco/astro-resume)
[![Package information: NPM license](https://img.shields.io/npm/l/@ayco/astro-resume)](https://www.npmjs.com/package/@ayco/astro-resume)
[![Package information: NPM downloads](https://img.shields.io/npm/dt/@ayco/astro-resume)](https://www.npmjs.com/package/@ayco/astro-resume)
Utilities for serializing data from server for use in the client. Utilities for serializing data from server for use in the client.
1. `Serialize` - Astro component that takes `id` and `data` 1. `Serialize` - Astro component that takes `id` and `data`
1. `deserialize()` - a function for use in the client that takes an `id` string and returns the `data` object 1. `deserialize(id: string)` - a function for use in the client that takes an `id` string and returns the `data` object
## Install via npm ## Installation & Examples
### Install via npm
On your [Astro](https://astro.build) project: On your [Astro](https://astro.build) project:
@ -20,7 +15,7 @@ On your [Astro](https://astro.build) project:
npm i @ayco/astro-resume npm i @ayco/astro-resume
``` ```
## Usage ### Usage
Serializing and deserializing basic primitive data Serializing and deserializing basic primitive data
@ -36,14 +31,14 @@ const data = {
<Serialize id="my-data" data={data} /> <Serialize id="my-data" data={data} />
<script> <script>
import {deserialize} from '@ayco/astro-resume'; import {deserialize} from '@ayco/astro-resume';
const data = deserialize('my-data'); const data = deserialize('my-data');
console.log(data) // {hello: 'world'} console.log(data) // {hello: 'world'}
</script> </script>
``` ```
## Type Safety ### Type Safety
You can define a type for the data and use it in the client script. You can define a type for the data and use it in the client script.
@ -62,21 +57,21 @@ export type Data = typeof data;
<Serialize id="my-data" data={data} /> <Serialize id="my-data" data={data} />
<script> <script>
import {deserialize} from '@ayco/astro-resume'; import {deserialize} from '@ayco/astro-resume';
/** /**
* reuse the type in the client * reuse the type in the client
* assuming this component's name is `ThisComponent.astro` * assuming this component's name is `ThisComponent.astro`
*/ */
import type {Data} from './ThisComponent.astro'; import type {Data} from './ThisComponent.astro';
const data = deserialize<Data>('my-data'); const data = deserialize<Data>('my-data');
console.log(data) // {hello: 'world', isOkay: true} console.log(data) // {hello: 'world', isOkay: true}
</script> </script>
``` ```
## Passing all Astro.props to client ### Passing all Astro.props to client
If you need to make all the component props to the client script: If you need to make all the component props to the client script:
@ -92,69 +87,27 @@ export interface Props {
<Serialize id="preferences" data={{...Astro.props}} /> <Serialize id="preferences" data={{...Astro.props}} />
<script> <script>
import {deserialize} from '@ayco/astro-resume'; import {deserialize} from '@ayco/astro-resume';
import type {Props} from './ThisComponent.astro'; import type {Props} from './ThisComponent.astro';
const {hello, isOkay} = deserialize<Props>('preferences'); const {hello, isOkay} = deserialize<Props>('preferences');
console.log(hello, isOkay); console.log(hello, isOkay);
</script> </script>
``` ```
## Serialize server data once, access everywhere ### Using a custom serializer and parser
If you have shared data that needs to be initialized from the server and accessed in several places on the client-side, you can use `Serialize` once and `deserialize` in any number of Astro components as long as they are in the same page. If you want to opt for more complex data, you can bring your custom serializer/parser.
In this example, an appConfig object is built and serialized in index.astro and accessed in child Astro components.
In index.astro:
```astro
import Serialize from "@ayco/astro-resume";
const appConfig = {
someClientSideKey: '1234hello',
}
export type AppConfig = typeof appConfig;
---
<Serialize id="app-config" data={appConfig} />
<Child />
```
In Child.astro:
```astro
<h1>I'm a child. I have access to the appConfig in index!</h1>
<GrandChild />
<script>
import {deserialize} from '@ayco/astro-resume';
import type {AppConfig} from '..pages/index.astro';
const data = deserialize<AppConfig>('app-config');
// ... do something with the app config
</script>
```
In GrandChild.astro:
```astro
<h1>I'm a grand child. I also have access to the appConfig in index!</h1>
<script>
import {deserialize} from '@ayco/astro-resume';
import type {AppConfig} from '..pages/index.astro';
const data = deserialize<AppConfig>('app-config');
// ... do something with the app config
</script>
```
## Using a custom serializer and parser
You can bring your own custom serializer/parser if you want to opt for more complex data handling.
Here's an example of serializing data that `JSON.stringify` cannot (e.g., Date or BigInt) using Rich Harris' [`devalue`](https://github.com/Rich-Harris/devalue): Here's an example of serializing data that `JSON.stringify` cannot (e.g., Date or BigInt) using Rich Harris' [`devalue`](https://github.com/Rich-Harris/devalue):
```astro ```astro
--- ---
import {stringify} from 'devalue'; import {stringify} from 'devalue';
import Serialize from "@ayco/astro-resume"; import Serialize from "../Serialize.astro";
const data = { const data = {
name: 'John Doe',
isOkay: true,
mood: null,
now: new Date(), now: new Date(),
age: BigInt('3218378192378') age: BigInt('3218378192378')
} }
@ -164,17 +117,17 @@ export type Data = typeof data;
<Serialize data={data} id="my-data" use={stringify} /> <Serialize data={data} id="my-data" use={stringify} />
<script> <script>
import {parse} from 'devalue'; import { parse } from 'devalue';
import {deserialize} from '@ayco/astro-resume'; import { deserialize } from '../deserialize';
import type {Data} from './index.astro'; import type { Data } from './index.astro';
const {age, now} = deserialize<Data>('my-data', parse); const data = deserialize<Data>('my-data', parse);
console.log(typeof age); // 'bigint' console.log(typeof data.age); // 'bigint'
console.log(now instanceof Date); // true console.log(data.now instanceof Date); // true
</script> </script>
``` ```
## Errors & Warning in `deserialize()` ### Errors & Warning in `deserialize()`
The `deserialize()` function may give you the following: The `deserialize()` function may give you the following:
1. **ERR: No match found** - there are no `JSON` scripts with the given ID 1. **ERR: No match found** - there are no `JSON` scripts with the given ID
@ -205,3 +158,4 @@ See the [TODO tracker](https://todo.sr.ht/~ayoayco/astro-resume) for planned wor
## Reporting Issues ## Reporting Issues
To report issues or request features, send a plain text email to [~ayoayco/astro-resume@todo.sr.ht](mailto:~ayoayco/astro-resume@todo.sr.ht) or file a ticket via [SourceHut](https://todo.sr.ht/~ayoayco/astro-resume) To report issues or request features, send a plain text email to [~ayoayco/astro-resume@todo.sr.ht](mailto:~ayoayco/astro-resume@todo.sr.ht) or file a ticket via [SourceHut](https://todo.sr.ht/~ayoayco/astro-resume)

View file

@ -1,6 +1,11 @@
import { defineConfig } from 'astro/config'; import { defineConfig } from 'astro/config';
import node from "@astrojs/node";
// https://astro.build/config // https://astro.build/config
export default defineConfig({ export default defineConfig({
output: "server", output: "server",
adapter: node({
mode: "standalone"
})
}); });

5794
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -1,13 +1,9 @@
{ {
"name": "@ayco/astro-resume", "name": "@ayco/astro-resume",
"author": "Ayo Ayco", "author": "Ayo Ayco",
"homepage": "https://ayco.io/sh/astro-resume", "homepage": "https://sr.ht/~ayoayco/astro-resume",
"repository": {
"type": "git",
"url": "https://git.sr.ht/~ayoayco/astro-resume"
},
"type": "module", "type": "module",
"version": "0.4.3", "version": "0.3.1",
"keywords": [ "keywords": [
"astro-component", "astro-component",
"css", "css",
@ -27,14 +23,11 @@
"start": "astro dev", "start": "astro dev",
"build": "astro build", "build": "astro build",
"preview": "astro preview", "preview": "astro preview",
"astro": "astro", "astro": "astro"
"publish:patch": "npm version patch && npm publish --access public",
"publish:minor": "npm version minor && npm publish --access public"
}, },
"devDependencies": { "dependencies": {
"devalue": "^5.1.1" "@astrojs/node": "^5.3.0",
}, "astro": "^2.8.4",
"peerDependencies": { "devalue": "^4.3.2"
"astro": "^5"
} }
} }

File diff suppressed because it is too large Load diff

View file

@ -21,15 +21,7 @@ let serializedData = '{}'
try { try {
serializedData = use ? use(data) : JSON.stringify(data); serializedData = use ? use(data) : JSON.stringify(data);
} catch(err) { } catch(err) {
/** throw Error(err)
* ERR: data is unserializable
* - You might need a custom serializer/parser for complex data
* - Usage examples in 👉 https://git.sr.ht/~ayoayco/astro-resume#astro-resume
*/
throw Error(`astro-resume ERR: Data unserializable
- You might need a custom serializer/parser for complex data
- Usage examples in 👉 https://git.sr.ht/~ayoayco/astro-resume#astro-resume
`, err)
} }
--- ---

View file

@ -4,13 +4,35 @@
* @param parser Custom parser to be used * @param parser Custom parser to be used
* @returns The deserialized JSON data * @returns The deserialized JSON data
* @see Usage examples in 👉 https://git.sr.ht/~ayoayco/astro-resume#astro-resume * @see Usage examples in 👉 https://git.sr.ht/~ayoayco/astro-resume#astro-resume
**/ * @example
*
* To make all `Astro.props` available in your client script:
*
* ```astro
* ---
* import Serialize from "@ayco/astro-resume";
* export interface Props {
* hello: string;
* isOkay: boolean;
* }
* ---
*
* <Serialize id="preferences" data={{...Astro.props}} />
*
* <script>
* import {deserialize} from '@ayco/astro-resume';
* import type {Props} from './ThisComponent.astro';
* const {hello, isOkay} = deserialize<Props>('preferences');
* console.log(hello, isOkay);
* </script>
* ```
**/
export function deserialize<T = any>(id: string, parser?: (serialized: string)=>any): T { export function deserialize<T = any>(id: string, parser?: (serialized: string)=>any): T {
const elements = document.querySelectorAll<HTMLScriptElement>(`script#${id}[type="application/json"]`); const elements = document.querySelectorAll<HTMLScriptElement>(`script#${id}[type="application/json"]`);
if (elements?.length > 0) { if (elements?.length > 0) {
if (elements?.length > 1) if (elements?.length > 1)
console.warn(`astro-resume WARN: Multiple matches for "${id}". The function will parse the first one.`) console.warn(`WARNING: Multiple matches for "${id}". There are ${elements?.length} matches found for ID: "${id}". The function will parse the first match found.`)
const element = elements[0]; const element = elements[0];
@ -20,7 +42,7 @@ export function deserialize<T = any>(id: string, parser?: (serialized: string)=>
: JSON.parse(element.textContent) : JSON.parse(element.textContent)
} }
throw Error(`astro-resume ERR: No match found. throw Error(`ERR: No match found.
"deserialize('${id}')" did not find any data. "deserialize('${id}')" did not find any data.
Check that the following are correct: Check that the following are correct:
- The Serialize component is used with correct props - The Serialize component is used with correct props

1
src/env.d.ts vendored
View file

@ -1,2 +1 @@
/// <reference path="../.astro/types.d.ts" />
/// <reference types="astro/client" /> /// <reference types="astro/client" />

View file

@ -1,13 +1,13 @@
--- ---
import { stringify } from 'devalue';
import Serialize from "../Serialize.astro"; import Serialize from "../Serialize.astro";
import { stringify } from "devalue";
const data = { const data = {
nameStr: "John Doe", name: 'John Doe',
isOkayBool: true, isOkay: true,
moodNull: null, mood: null,
nowDate: new Date(), now: new Date(),
ageBigInt: BigInt("3218378192378"), age: BigInt('3218378192378')
}; }
export type Data = typeof data; export type Data = typeof data;
--- ---
@ -15,30 +15,13 @@ export type Data = typeof data;
<Serialize data={data} id="my-data" use={stringify} /> <Serialize data={data} id="my-data" use={stringify} />
<script> <script>
import { deserialize } from "../deserialize"; import { deserialize } from '../deserialize';
import { parse } from "devalue"; import { parse, stringify } from 'devalue';
import type { Data } from "./index.astro"; import type { Data } from './index.astro';
const data = deserialize<Data>("my-data", parse); const data = deserialize<Data>('my-data', parse);
console.log(data); console.log(data);
console.log(typeof data.age);
Object.keys(data).forEach((key) => console.log(data.now instanceof Date);
console.log(key, data[key], typeof data[key]) document.getElementById("render-here").innerHTML = stringify(data)
);
// render table to render-here
const table = document.createElement("table");
const tbody = document.createElement("tbody");
table.appendChild(tbody);
Object.keys(data).forEach((key) => {
const tr = document.createElement("tr");
const tdKey = document.createElement("td");
const tdValue = document.createElement("td");
tdKey.textContent = key;
tdValue.textContent = data[key];
tr.appendChild(tdKey);
tr.appendChild(tdValue);
tbody.appendChild(tr);
});
document.getElementById("render-here").appendChild(table);
</script> </script>