Skip to content

v0.0.8

Pre-release
Pre-release

Choose a tag to compare

@suchipi suchipi released this 15 Feb 07:01
· 735 commits to main since this release

This release brings several exciting features, but the star of the show is definitely npm support!

Highlights

NPM support

You can now import packages directly from npm without needing to run npm install by importing using the npm: protocol:

import * as Preact from "npm:preact@^10.5.0";

Or, if you want to work with local npm packages in a node_modules directory, you can install them as usual and then load them with either require or import:

$ npm install --save preact@^10.5.0
const Preact = require("preact");

Please be aware that although many npm packages will work, packages which use Node.js-specific builtins like fs, path, or vm will not function unless you shim those builtin modules via Module.define. I may include partial shims for common Node.js builtins like these in the future.

Import from http/https

You can now import modules from http/https URLs:

import * as Something from "https://something.example.com/something.js";

As always, please consult the typedefs by running yavascript --print-types in order to see the documentation and type signatures of all APIs included in yavascript.

Details

Additions

  • You can now import modules directly from http/https URLs. They will be fetched each time the script is evaluated. I will probably add caching options in the future.
    import * as Something from "https://something.example.com/something.js";
  • You can now import any npm package without installing it first, using the npm: prefix in an import URL. For example:
    import * as Preact from "npm:preact@^10.5.0";
    This feature relies on Skypack, which converts CJS into ESM in the npm packages it serves.
    • npm packages will be fetched from the Skypack cdn each time your script is evaluated. I will probably add caching options in the future.
  • You can now construct Path objects with template literals by using Path.tag and/or Path.tagUsingBase
  • You can now pass { binary: true } to readFile to get an ArrayBuffer instead of a string
  • There is now preliminary support for ESM <-> CJS interop
    • If code appears to assign to exports or module.exports (static code analysis heuristic), then the value of module.exports will be made available as a named export named __cjsExports, and a named export named __isCjsModule will be present which is a boolean indicating whether module.exports or exports were modified when the module was loaded.
    • require detects the above situation and returns module.exports.__cjsExports instead of module.exports, when appropriate.
    • Import statements and dynamic import do not handle __cjsExports specially. You may have to read off of __cjsExports manually to get the values you want, when importing CommonJS files. Or you can use require to load them instead.
  • The node_modules module lookup resolution algorithm is now partially supported.
    • The "exports" field of package.json is not yet supported. However, the "main" field is supported.
    • If the package you want to import from only has an exports field, you can manually reach into the package to get the file it would export, ie import * as something from "some-package/dist/index.mjs"
  • A new yavascript global is available which can be used to detect whether code is running in yavascript. This global is an object which holds information about the running yavascript binary, including version, processor architecture, etc.
  • The transpilation functions yavascript uses when loading coffeescript/typescript/etc are now available as yavascript.compilers, eg. the function yavascript.compilers.jsx.
  • Several functions which accept string paths now also support Path objects in those places. Not all functions have support for this yet, though. Consult yavascript --print-types to understand which do and which don't.

Changes

  • The is and assert APIs have been changed significantly. Instead of various type-checking functions living as properties on both is and assert, they are now on a new types global, and should be passed to either is (which is now a function instead of an object) or assert.type (which is a new function). This is a breaking change.
    • This new types global also has functions for making compound types, like "and", "or", etc. It's based on pheno.
  • The QuickJS builtin modules std and os are now namespaced, and as such have been renamed to quickjs:std and quickjs:os. You should update your imports and requires accordingly. This is a breaking change.
  • Several APIs will now do runtime type checks on the values they receive to ensure that you're passing, for example, a string when you need to be passing a string. This allows us to have nicer error messages when an incorrect type is passed through.

Fixes

  • When running files specified via relative paths at the CLI, is no longer necessary to prefix the paths with ./ or ../. An unprefixed path will search in the current working directory.
  • The Node.js-compatibility API process.execPath was mistakenly using readlink on the result of the QuickJS os.execPath(), when it should have been using realpath. This has been fixed.

Caveats

  • http:, https:, and npm: imports rely on curl being available in your PATH. We (safely!) shell out to curl instead of including network fetching code in the yavascript binary to keep it lean and also to ensure you can get security updates for OpenSSL and stuff without having to wait for a new version of yavascript. If you don't have curl installed on your system, http:, https:, and npm: imports will fail.
  • In order to support using import and require interchangeably in any file without having to differentiate between scripts and modules, yavascript assumes all code is targeting the "module" goal. As such, strict mode is always on, and the toplevel this value is always undefined. This may cause some issues in some npm packages which expect to be run in non-strict mode.
  • Many npm packages depend on Node.js builtins like fs, path, util, or child_process. Those packages will not work in yavascript unless you shim those builtins by using Module.define. At some point in the future, I may add some small shims for the most common functionality of these builtins, but full Node.js compatibility is a non-goal.
  • The code to support Skypack relies on the fact that Skypack's sub-dependency files all have paths prefixed with /-/. The module loader will treat any path starting with /-/ as being from Skypack. This may cause problems in the unlikely event that you have a folder named - in the root of your filesystem, because its contents will be "shadowed" by Skypack. I hope to remove this hack in the future by changing the module loader to be aware of the "current origin", like web browsers are.

Git Diff

v0.0.7...v0.0.8