ECMAScript modules
Fixes #1306. Migrating our dependencies to ESM made it possible to migrate the compiler and frontend as well, alongside internal utility and scripts. This is a breaking change for consumers of the compiler API (i.e. transforms), but not for command line usage. Viable strategies to account for the changes are:
-
Migrate any code utilizing compiler APIs to ESM as well:
import assemblyscript from "assemblyscript"; ...
-
Utilize a dynamic import while consuming code remains in its current module format:
const assemblyscript = (await import("assemblyscript")).default; ... // or import("assemblyscript").then(({ default: assemblyscript }) => { ... });
Due to this change, older versions of Node.js may need to be upgraded (LTS v16 or stable v17 are recommended).
Running the compiler on the Web with ESM
Prior, we provided a browser SDK that made use of the AMD module format to load the components necessary to run the compiler on the Web. With the switch to ESM, it is not necessary anymore to provide a separate SDK, but native browser functionality can now be used to utilize the compiler in browsers. To ease the transition, the build system outputs an example dist/web.html
template with all the right versions in <script ...>
tags. Alongside, it also sets up es-module-shims
for import maps support as is currently necessary to support browsers other than those based on Chromium. General outline is:
<script async src="url/to/es-module-shims"></script>
<script type="importmap">
{
"imports": {
"binaryen": "url/to/binaryen",
"long": "url/to/long",
"assemblyscript": "url/to/assemblyscript"
}
}
</script>
<script type="module">
import asc from "url/to/asc";
...
</script>
Asynchronous compiler APIs
Prior, programmatically executing for example asc.main
was synchronous despite accepting a callback. The relevant APIs are now asynchronous, making use of the opportunity to perform asynchronous I/O under the hood, and as such return a promise with the compilation result instead of accepting a callback.
const { error, stdout, stderr } = await asc.main([ ... ], { ... });
...
It is no longer necessary to override stdout
and stderr
, since the default has been switched to return a memory stream. If binding to the Node.js console is desired, which is rare, the behavior can be overridden to the previous by specifying { stdout: process.stdout, stderr: process.stderr }
in API options.
In addition, transform hooks gained the ability to evaluate asynchronously when being async
/ returning a promise.
Unification of ===
and ==
Fixes #856. Closes #1111. The semantics of ===
and !==
are redundant in AssemblyScript since comparing two values of different types is not permitted anyhow. In the early days of the compiler we hence repurposed the operator to perform what seemed like a useful operation, that is test for identity equality (the exact same object). Doing so, however, introduced a subtle footgun into the language for those coming from TypeScript, and now has been removed.
Means: ===
is now the same as ==
, !==
is now the same as !=
, largely matching intuition.
Deprecation of the loader
The loader was a stopgap solution intended to keep glue code minimal until WebAssembly integrates natively with the rest of the Web platform. Sadly, we made a bet there that didn't materialize, and the loader has now been deprecated with the compiler now supporting static generation of glue code with the --bindings
option.
Available bindings are:
--bindings, -b Specifies the bindings to generate (.js + .d.ts).
esm JavaScript bindings & typings with ESM integration.
raw Like esm, but exports just the instantiate function.
Useful where modules are meant to be instantiated
multiple times or non-ESM imports must be provided.
Generated JavaScript bindings support the data types
Type | Strategy | Description |
---|---|---|
Number | By value | Basic types except 64-bit integers |
BigInt | By value | 64-bit integers via js-bigint-integration |
String | Copy | |
ArrayBuffer | Copy | |
TypedArray | Copy | Any kind |
Array | Copy | Any kind |
StaticArray | Copy | Any kind |
Object | Copy | Plain objects (no constructor or non-public fields). Can opt-out by providing an empty constructor. |
Internref | By value | Reference counted pointer via FinalizationRegistry. Essentially anything that isn't a plain object. |
Externref | By value | Via reference-types |
For now, only top-level functions, globals and enums receive bindings. Classes do not (yet). Bindings automagically utilize exported runtime helpers so users don't have to.
Preserving side-effects in static type checks
Fixes #531. The static type checks isInteger
, isFloat
, isBoolean
, isSigned
, isReference
, isString
, isArray
, isArrayLike
, isFunction
, isNullable
, isConstant
, isManaged
, isVoid
, lengthof
, nameof
and idof
accept either a type argument, an argument or both. In the uncommon case of providing an argument, that is not solely operating on a type, these builtins now preserve side-effects of the argument which is safer but may prevent compile-time branch elimination in such cases.
Unified consumption of the assemblyscript
package
Entrypoints for the various components are now:
assemblyscript
as beforeassemblyscript/asc
to obtain the compiler frontendassemblyscript/transform
to obtain the transform base classassemblyscript/binaryen
to obtain the exact instance of Binaryen usedassemblyscript/util/*.js
to obtain various utility, i.e. for configuration parsing
Removal of ascMain
in package.json
Fixes #1954. As it turned out, specifying an alternative entry point in package.json
led to more issues than it solved, often not finding files and types because existing tooling does not recognize it. As such, this mechanism has been removed in favor of plain node-style resolution, i.e. import { x } from "myPackage/assembly"
, which is not susceptible to these problems.
Removal of experimental --extension
CLI option
See #1003. While it is likely that discussion about using another file extension will continue in the future, the CLI option was meant for experimentation, had various issues and lately became stale. Hence it has been removed to simplify matters on common ground.
Replaced --explicitStart
CLI option with --exportStart NAME
Fixes #2099. The new option is more general in that it also accepts the desired export name to use for the start function. Typical options are:
--exportStart _start
for a WASI command. This is equivalent to the former--explicitStart
.--exportStart _initialize
for a WASI reactor.--exportStart myCustomStartFunctionName
for anything else.
Note that the start function, no matter how it is named, must always be called before any other exports to initialize the module.
Renamed untouched/optimized to debug/release
Default compilation targets (generated) for projects are now named debug and release to better fit their purpose and to have only one set of names to remember.
Enabled various WebAssembly features
Some meanwhile standardized features have been enabled by default:
- Nontrapping float to int conversions brings additional conversion operations.
- Bulk Memory replaces fallback implementations of
memory.fill
andmemory.copy
.
Note that we are still holding back on enabling SIMD by default as it is not yet supported in Safari, but one can already play with it using --enable simd
.
Reworked development workflow
Prior, AssemblyScript utilized ts-node
in development to lessen overhead from recompilation on changes. This approach turned out to be not viable anymore due to various issues with modern language features and has been dropped, alongside webpack
for final builds, and replaced with esbuild
. The new development workflow is to execute npm run watch
which will automatically and quickly produce builds. As a side effect, workarounds and dependencies to support the prior development workflow could be dropped.
And the kitchen sink
- Various clean ups have been performed, with no longer needed files and long deprecated APIs being removed
- Support for older Node.js versions not supporting ECMAScript modules has been dropped
- The WebIDL and Asm.js targets have been dropped as they were of little use and largely unmaintained
- The
--listFiles
(not Wasm-target compatible) and--traceResolution
(now tested programmatically) CLI options have been removed. - The Binaryen dependency now uses Wasm builds and has been significantly sped up by enabling more optimizations. Optimizing the AssemblyScript compiler itself now only takes about a third of the time.