Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions examples/components/node-compat/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
node_modules
dist
57 changes: 57 additions & 0 deletions examples/components/node-compat/index.js
Copy link
Collaborator

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 sure index.js is 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.md would also be nice to list this example next to the others.

Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import { URL } from "node:url";
Copy link
Collaborator

Choose a reason for hiding this comment

The 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 node:* import will actually end up coming from?

import * as querystring from "node:querystring";

const testUrls = [
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
const testUrls = [
const TEST_URLS = [

"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
Copy link
Collaborator

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 building a string here rather than console.loging?


export function printUrlBufferInfo(urlString) {
const buffer = Buffer.from(urlString, "utf8");
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A note here on the fact that Buffer is actually a NodeJS-ism rather than a web platform or standards backed global object that is present.

An explicit import of Buffer from node:buffer might be nice as well.

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
Copy link
Collaborator

Choose a reason for hiding this comment

The 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);
});
},
};
22 changes: 22 additions & 0 deletions examples/components/node-compat/package.json
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"
}
}
25 changes: 25 additions & 0 deletions examples/components/node-compat/rollup.config.mjs
Copy link
Collaborator

Choose a reason for hiding this comment

The 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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would you mind mind adding a comment (likely before the defineEnv line?) about Unenv and what the effect of this line is/how it changes the project and what it makes possible?


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(),
],
};
3 changes: 3 additions & 0 deletions examples/components/node-compat/run-transpiled.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import { run } from "./dist/transpiled/component.js";

run.run();
5 changes: 5 additions & 0 deletions examples/components/node-compat/wit/component.wit
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;
}
261 changes: 261 additions & 0 deletions examples/components/node-compat/wit/deps/wasi-cli-0.2.6/package.wit
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;
}
Loading
Loading