-
Notifications
You must be signed in to change notification settings - Fork 96
Added node compat example #1223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,2 @@ | ||
| node_modules | ||
| dist |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -0,0 +1,57 @@ | ||||||
| import { URL } from "node:url"; | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind adding a comment about why this line and teh one below it are special/the focus of the example and where the |
||||||
| import * as querystring from "node:querystring"; | ||||||
|
|
||||||
| const testUrls = [ | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| "https://example.com/api/users?page=1&limit=10&sort=name", | ||||||
| "https://shop.example.com:8080/products/electronics?category=laptops&price_max=2000#reviews", | ||||||
| "http://localhost:3000/admin/dashboard?token=abc123&debug=true", | ||||||
| ]; | ||||||
|
|
||||||
| export function urlParts(urlString) { | ||||||
| const url = new URL(urlString); | ||||||
| return { | ||||||
| urlString, | ||||||
| protocol: url.protocol, | ||||||
| host: url.host, | ||||||
| hostname: url.hostname, | ||||||
| port: url.port, | ||||||
| pathname: url.pathname, | ||||||
| hash: url.hash, | ||||||
| queries: querystring.parse(url.search.substring(1)), | ||||||
| }; | ||||||
| } | ||||||
|
|
||||||
| export function printUrlParts(urlParts) { | ||||||
| console.log(`URL: ${urlParts.urlString}`); | ||||||
| console.log(` Protocol: ${urlParts.protocol}`); | ||||||
| console.log(` Host: ${urlParts.host}`); | ||||||
| console.log(` Hostname: ${urlParts.hostname}`); | ||||||
| console.log(` Port: ${urlParts.port || "(default)"}`); | ||||||
| console.log(` Pathname: ${urlParts.pathname}`); | ||||||
| console.log(` Hash: ${urlParts.hash || "(none)"}`); | ||||||
| console.log(` Queries:`); | ||||||
| for (const [key, value] of Object.entries(urlParts.queries)) { | ||||||
| console.log(` ${key}: ${value}`); | ||||||
| } | ||||||
| console.log(); | ||||||
| } | ||||||
|
Comment on lines
+24
to
+37
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about building a string here rather than |
||||||
|
|
||||||
| export function printUrlBufferInfo(urlString) { | ||||||
| const buffer = Buffer.from(urlString, "utf8"); | ||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A note here on the fact that An explicit import of Buffer from |
||||||
| console.log(" Buffer info:"); | ||||||
| console.log(` Length: ${buffer.length} bytes`); | ||||||
| console.log(` Hex: ${buffer.toString("hex")}`); | ||||||
| console.log(` Base64: ${buffer.toString("base64")}`); | ||||||
| console.log(); | ||||||
| } | ||||||
|
Comment on lines
+39
to
+46
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same note about building a string here |
||||||
|
|
||||||
| // Export the `wasi:cli/run` interface | ||||||
| export const run = { | ||||||
| run() { | ||||||
| testUrls.forEach((urlString) => { | ||||||
| const parts = urlParts(urlString); | ||||||
| printUrlParts(parts); | ||||||
| printUrlBufferInfo(urlString); | ||||||
| }); | ||||||
| }, | ||||||
| }; | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| { | ||
| "name": "compat", | ||
| "description": "", | ||
| "main": "index.js", | ||
| "type": "module", | ||
| "scripts": { | ||
| "build": "rollup -c && jco componentize -w wit -o dist/component.wasm dist/component.js", | ||
| "transpile": "jco transpile dist/component.wasm -o dist/transpiled", | ||
| "run-transpiled": "node run-transpiled.js ", | ||
| "all": "npm run build; npm run transpile; npm run run-transpiled" | ||
| }, | ||
| "keywords": [], | ||
| "dependencies": { | ||
| "@bytecodealliance/jco": "^1.15.4", | ||
| "@rollup/plugin-alias": "^6.0.0", | ||
| "@rollup/plugin-commonjs": "^29.0.0", | ||
| "@rollup/plugin-inject": "^5.0.5", | ||
| "@rollup/plugin-node-resolve": "^16.0.3", | ||
| "rollup": "^4.57.0", | ||
| "unenv": "^2.0.0-rc.24" | ||
| } | ||
| } |
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you consider using Rolldown here rather than Rollup? Adopting more of the oxc stack is definitely a long term goal, and you may be able to remove some dependencies (and have things run faster). The config generally looks pretty similar and rolldown is explicitly supported by unenv in the docs) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,25 @@ | ||
| import nodeResolve from "@rollup/plugin-node-resolve"; | ||
| import commonjs from '@rollup/plugin-commonjs'; | ||
| import alias from '@rollup/plugin-alias'; | ||
| import inject from '@rollup/plugin-inject'; | ||
| import { defineEnv } from "unenv"; | ||
|
|
||
| const { env } = defineEnv({}); | ||
|
Comment on lines
+5
to
+7
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would you mind mind adding a comment (likely before the |
||
|
|
||
| export default { | ||
| input: "index.js", | ||
| external: /wasi:.*/, | ||
| output: { | ||
| file: "dist/component.js", | ||
| format: "esm", | ||
| inlineDynamicImports: true, | ||
| }, | ||
| plugins: [ | ||
| inject(env.inject), | ||
| alias({ | ||
| entries: env.alias, | ||
| }), | ||
| commonjs(), | ||
| nodeResolve(), | ||
| ], | ||
| }; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| import { run } from "./dist/transpiled/component.js"; | ||
|
|
||
| run.run(); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| package example:node-compat; | ||
|
|
||
| world component { | ||
| export wasi:cli/run@0.2.6; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,261 @@ | ||
| package wasi:cli@0.2.6; | ||
|
|
||
| @since(version = 0.2.0) | ||
| interface environment { | ||
| /// Get the POSIX-style environment variables. | ||
| /// | ||
| /// Each environment variable is provided as a pair of string variable names | ||
| /// and string value. | ||
| /// | ||
| /// Morally, these are a value import, but until value imports are available | ||
| /// in the component model, this import function should return the same | ||
| /// values each time it is called. | ||
| @since(version = 0.2.0) | ||
| get-environment: func() -> list<tuple<string, string>>; | ||
|
|
||
| /// Get the POSIX-style arguments to the program. | ||
| @since(version = 0.2.0) | ||
| get-arguments: func() -> list<string>; | ||
|
|
||
| /// Return a path that programs should use as their initial current working | ||
| /// directory, interpreting `.` as shorthand for this. | ||
| @since(version = 0.2.0) | ||
| initial-cwd: func() -> option<string>; | ||
| } | ||
|
|
||
| @since(version = 0.2.0) | ||
| interface exit { | ||
| /// Exit the current instance and any linked instances. | ||
| @since(version = 0.2.0) | ||
| exit: func(status: result); | ||
|
|
||
| /// Exit the current instance and any linked instances, reporting the | ||
| /// specified status code to the host. | ||
| /// | ||
| /// The meaning of the code depends on the context, with 0 usually meaning | ||
| /// "success", and other values indicating various types of failure. | ||
| /// | ||
| /// This function does not return; the effect is analogous to a trap, but | ||
| /// without the connotation that something bad has happened. | ||
| @unstable(feature = cli-exit-with-code) | ||
| exit-with-code: func(status-code: u8); | ||
| } | ||
|
|
||
| @since(version = 0.2.0) | ||
| interface run { | ||
| /// Run the program. | ||
| @since(version = 0.2.0) | ||
| run: func() -> result; | ||
| } | ||
|
|
||
| @since(version = 0.2.0) | ||
| interface stdin { | ||
| @since(version = 0.2.0) | ||
| use wasi:io/streams@0.2.6.{input-stream}; | ||
|
|
||
| @since(version = 0.2.0) | ||
| get-stdin: func() -> input-stream; | ||
| } | ||
|
|
||
| @since(version = 0.2.0) | ||
| interface stdout { | ||
| @since(version = 0.2.0) | ||
| use wasi:io/streams@0.2.6.{output-stream}; | ||
|
|
||
| @since(version = 0.2.0) | ||
| get-stdout: func() -> output-stream; | ||
| } | ||
|
|
||
| @since(version = 0.2.0) | ||
| interface stderr { | ||
| @since(version = 0.2.0) | ||
| use wasi:io/streams@0.2.6.{output-stream}; | ||
|
|
||
| @since(version = 0.2.0) | ||
| get-stderr: func() -> output-stream; | ||
| } | ||
|
|
||
| /// Terminal input. | ||
| /// | ||
| /// In the future, this may include functions for disabling echoing, | ||
| /// disabling input buffering so that keyboard events are sent through | ||
| /// immediately, querying supported features, and so on. | ||
| @since(version = 0.2.0) | ||
| interface terminal-input { | ||
| /// The input side of a terminal. | ||
| @since(version = 0.2.0) | ||
| resource terminal-input; | ||
| } | ||
|
|
||
| /// Terminal output. | ||
| /// | ||
| /// In the future, this may include functions for querying the terminal | ||
| /// size, being notified of terminal size changes, querying supported | ||
| /// features, and so on. | ||
| @since(version = 0.2.0) | ||
| interface terminal-output { | ||
| /// The output side of a terminal. | ||
| @since(version = 0.2.0) | ||
| resource terminal-output; | ||
| } | ||
|
|
||
| /// An interface providing an optional `terminal-input` for stdin as a | ||
| /// link-time authority. | ||
| @since(version = 0.2.0) | ||
| interface terminal-stdin { | ||
| @since(version = 0.2.0) | ||
| use terminal-input.{terminal-input}; | ||
|
|
||
| /// If stdin is connected to a terminal, return a `terminal-input` handle | ||
| /// allowing further interaction with it. | ||
| @since(version = 0.2.0) | ||
| get-terminal-stdin: func() -> option<terminal-input>; | ||
| } | ||
|
|
||
| /// An interface providing an optional `terminal-output` for stdout as a | ||
| /// link-time authority. | ||
| @since(version = 0.2.0) | ||
| interface terminal-stdout { | ||
| @since(version = 0.2.0) | ||
| use terminal-output.{terminal-output}; | ||
|
|
||
| /// If stdout is connected to a terminal, return a `terminal-output` handle | ||
| /// allowing further interaction with it. | ||
| @since(version = 0.2.0) | ||
| get-terminal-stdout: func() -> option<terminal-output>; | ||
| } | ||
|
|
||
| /// An interface providing an optional `terminal-output` for stderr as a | ||
| /// link-time authority. | ||
| @since(version = 0.2.0) | ||
| interface terminal-stderr { | ||
| @since(version = 0.2.0) | ||
| use terminal-output.{terminal-output}; | ||
|
|
||
| /// If stderr is connected to a terminal, return a `terminal-output` handle | ||
| /// allowing further interaction with it. | ||
| @since(version = 0.2.0) | ||
| get-terminal-stderr: func() -> option<terminal-output>; | ||
| } | ||
|
|
||
| @since(version = 0.2.0) | ||
| world imports { | ||
| @since(version = 0.2.0) | ||
| import environment; | ||
| @since(version = 0.2.0) | ||
| import exit; | ||
| @since(version = 0.2.0) | ||
| import wasi:io/error@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:io/poll@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:io/streams@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import stdin; | ||
| @since(version = 0.2.0) | ||
| import stdout; | ||
| @since(version = 0.2.0) | ||
| import stderr; | ||
| @since(version = 0.2.0) | ||
| import terminal-input; | ||
| @since(version = 0.2.0) | ||
| import terminal-output; | ||
| @since(version = 0.2.0) | ||
| import terminal-stdin; | ||
| @since(version = 0.2.0) | ||
| import terminal-stdout; | ||
| @since(version = 0.2.0) | ||
| import terminal-stderr; | ||
| @since(version = 0.2.0) | ||
| import wasi:clocks/monotonic-clock@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:clocks/wall-clock@0.2.6; | ||
| @unstable(feature = clocks-timezone) | ||
| import wasi:clocks/timezone@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:filesystem/types@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:filesystem/preopens@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/network@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/instance-network@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/udp@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/udp-create-socket@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/tcp@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/tcp-create-socket@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/ip-name-lookup@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:random/random@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:random/insecure@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:random/insecure-seed@0.2.6; | ||
| } | ||
| @since(version = 0.2.0) | ||
| world command { | ||
| @since(version = 0.2.0) | ||
| import environment; | ||
| @since(version = 0.2.0) | ||
| import exit; | ||
| @since(version = 0.2.0) | ||
| import wasi:io/error@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:io/poll@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:io/streams@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import stdin; | ||
| @since(version = 0.2.0) | ||
| import stdout; | ||
| @since(version = 0.2.0) | ||
| import stderr; | ||
| @since(version = 0.2.0) | ||
| import terminal-input; | ||
| @since(version = 0.2.0) | ||
| import terminal-output; | ||
| @since(version = 0.2.0) | ||
| import terminal-stdin; | ||
| @since(version = 0.2.0) | ||
| import terminal-stdout; | ||
| @since(version = 0.2.0) | ||
| import terminal-stderr; | ||
| @since(version = 0.2.0) | ||
| import wasi:clocks/monotonic-clock@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:clocks/wall-clock@0.2.6; | ||
| @unstable(feature = clocks-timezone) | ||
| import wasi:clocks/timezone@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:filesystem/types@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:filesystem/preopens@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/network@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/instance-network@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/udp@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/udp-create-socket@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/tcp@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/tcp-create-socket@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:sockets/ip-name-lookup@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:random/random@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:random/insecure@0.2.6; | ||
| @since(version = 0.2.0) | ||
| import wasi:random/insecure-seed@0.2.6; | ||
|
|
||
| @since(version = 0.2.0) | ||
| export run; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What do you think about renaming this file to
component.js? I'm not sureindex.jsis very descriptive/fits the server-side paradigm.Also, would you mind adding a descriptive README that matches some of the other examples? Updating
components/README.mdwould also be nice to list this example next to the others.