• Stars
    star
    891
  • Rank 51,222 (Top 2 %)
  • Language
    HTML
  • License
    BSD 2-Clause "Sim...
  • Created over 6 years ago
  • Updated over 1 year ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Built In Modules Proposal (aka JavaScript Standard Library)

Proposal for adding a mechanism for enabling a more extensive standard library in JavaScript via a collection of built in modules. With this infrastructure in place it will be possible to start iterating on standard library features as additional modules.

Table of Contents

Scope

The goal of this proposal is to define a mechanism for enabling a more extensive standard library in JavaScript than what is available now. Currently it is the case if new properties are added to the language, they are added someplace in the global object.

This proposal would not change the behavior of any existing code or add any new syntax, except possibly syntax needed for importing the standard library code. There likely will be new properties and methods added to enable this feature.

The contents of the standard library is tangential to this proposal, and would be built and expanded upon in later efforts. Such a library would only cover features which would be useful in JavaScript in general, not things which are tied to the web platform. Host environments built on JavaScript could provide their own library components. (A good heuristic: if something would make sense on a web browser but not in node or on embedded devices or robots, it probably isn't in scope.) See #16 for discussion of the extent and contents of the library.

Motivation

Most programming languages have core language features (syntax, operators, primitives etc.) along with a standard library of commonly used functionality. Developers are able to use this library in their programs immediately because the library is bundled with the runtime.

The JavaScript language does not have a standard library. As a result new functionality is added to the global object, or developers find and adopt libraries that they bundle with the rest of their application. Because these libraries need to be included in every program instead of being provided by the runtime, the code size of applications grow, with users paying the cost of downloading and parsing the common library components. This can increase downloading times and makes it nearly impossible for JavaScript engines to cache the common code.

JavaScript programs run on a variety of clients with different runtime implementations and versions. It is quite likely that the bundled library code needs to account for different host environments, thus increasing code size. Library code bundled with the JavaScript engine could be optimizied for the target host environment.

Proposed Solution

To enable developers to access common functionality provided by the JavaScript engine we propose creating modules built into the host. This will allow library code bundled with the program to shift towards being available on the host JavaScript implementations.

Disclaimer: This proposal covers adding a mechanism for enabling a standard library in JavaScript implementations, it does not describe its contents. This is considered a tangential effort that would be built and expanded upon in the future when a mechanism for accessing it is in place.

Having a standard library readily available at runtime means programs won't have to include the functionality available in the standard library, reducing the download and startup cost of the program. The functionality will also be standardized across implementations giving developer consistency in quality, behavior and speed. For some JavaScript engines, built in modules will allow them to reduce application memory footprint

Although JavaScript engines already has the notion of a common library through the global object, the standard library components can be accessed using the current asynchronous import() API. Module scripts can also access built in library components using the import syntax. Traditional script code will be able to access these same standard library components through a new synchronous API, importNow(). Most of these mechanism should already be familiar to developers, allowing them to opt-in to this built in library functionality with little effort.

Modules for the standard library should be able to be written in plain JavaScript for the most part but for hot pieces of code the engine could provide a native implementation.

Import Semantics

To import modules from the standard library the engine has to be able to distinguish between standard library modules and other (user defined) modules. To allow the engine to do this standard library modules will use a prefix in the module identifier string. This is prefered over other alternatives because it is does not introduce new syntax for loading standard library modules and stays close to the import statement developers should already be familiar with.

Namespace

The js: prefix will be reserved as the namespace for the JavaScript language only and will be governed by TC39, making the standard library a true JavaScript standard library. This will allow the committee to work safely within this namespace when designing and developing the standard library over time.

Alternatives for distinguishing standard modules are documented in Appendix A.

By creating a namespaces specifically for the JavaScript standard library, developers will know what to expect when importing from using the js: prefix across different implementations and can be assured the same modules are available across these implementations (not considering implementation constraints, vendor timelines or version differences).

It is completely feasable that more namespaces are introduced which are goverened by other standards bodies or organizations. However it is important that these namespaces stay independent of each other to avoid conflicts, hamper development within namespaces due to outside pollution or time constraints due to dependencies on other organizations.

The namespace used for the JavaScript standard library will be registered with IANA to prevent collisions in the future. Any other organization introducing a namespace prefix would be encouraged to do the same.

Freezing Exports

All exported objects and classes from the standard library will have their prototype frozen. This will prevent prototypes from imported objects to be modified outside of the module causing prototype pollution.

In the past the committee had to make concessions to maintain web compatibility when adding new functionality to built-in objects. By freezing the prototype of standard library exports, it will no longer be possible for third party code to modify or extending library code in a possibly incompatible way. This will allow for more flexibility when designing and developing the standard library. Extending standard library classes and objects can still be done using extend or Object.create.

We can start off by conventionally enforcing Object.freeze on exported Objects from standard library modules. If this turns out to be hard to check and enforce a separate proposal can be created to describe automatically freezing prototypes at the module boudary for standard library modules.

Note, the current direction is to freeze module contents thus requiring shimming code to wrap module classes and objects. Given some discussion around this point, it may be dropped from the proposal before built in modulesa re added to the standard.

Module Resolution

To allow the JavaScript engine to participate in module resolution and loading the HostResolveModuleIdentifier Abstract Operation should be changed to allow more than one resolver. The resolvers are arranged in a chain and consulted by the engine one by one to resolve a requested ModuleIdentifier. This mechanism is heavily inspired by Pythons importing system for modules.

The implementation of the chain will be hidden inside the engine and will provide the same guarantees HostResolveModuleIdentifier currently does:

  • It must return an instance of ModuleRecord
  • It must throw an error if a ModuleRecord cannot be created
  • It must be idempotent for pair of (ModuleIdentifier, ReferencingModule)

Importing is done in two phases: resolution and loading. Resolution is done through objects implementing the ResolveModuleIdentifier operation and loading is done through objects implementing the LoadModuleIdentifier operation. Objects implementing both operations are referred to as importers.

Module Resolution and Loading Chain

Multiple importers can be registered with the engine and will be appended to the chain. The engine will always register the internal JavaScript Standard Library importer first to make sure it is at the front of the chain.

During the resolution step (phase 1) importers perform the ResolveModuleIdentifier operation in order of registration. This operation results in a ModuleResolutionRecord that is passed along the chain and can be used by subsequent importers.

After the resolution step the loading step (phase 2) is invoked. During this step the importers are visited in reverse order to perform the LoadModuleIdentifier operation to try and load the requested ModuleIdentifier. The operation is passed the ModuleResolutionRecords from the resolution step. When the ModuleIdentifier can be loaded a full ModuleRecord is returned and the chain is exited immediately. When no ModuleRecord is produced the next importer is consulted until the chain is exhausted, resulting in a ModuleNotFound error.

Shimming / Polyfilling

During the loading step (phase 2) the chain is traversed in reverse order to allow for higher ranked (e.g. registered later) importers to possibly override lower ranked importers. This will allow the host for example to override standard library modules and achieve shimming / polyfilling.

Alternatively, provisions are made for code to import a built-in module, shim it and update the host module table to point at the shimmed version. This can be do repeatively so that shims / polyfills can be layored on top of each other.

There are three use cases that a polyfilling solution for the standard library should support:

  • Add missing parts of the standard library
  • Update incomplete implementations
  • Redact parts of a library component.

Polyfilling is intended to cover these three use cases only.

For the web platform polyfilling could be done using the Import Maps Proposal. A resolver registered by the embedder (a web browser in this case) could check the import map to see if a standard library ModuleIdentifier should be redirected to another implementation.

Related Efforts

This subject has been talked about in the past and has related efforts:

Frequently Asked Questions

Coming Soon™

Appendices

A. Distinguishing Standard Library Modules

One of the requirements for the standard library is being able to distinguish when a module is user defined and when it should be loaded from the standard library. There are a lot of approaches to doing this and this section contains alternatives considered to the recommendation earlier in the proposal.

Important: The code samples and modules used in the examples are purely for illustrative purposes

Identifier Based

When importing a module the ModuleSpecifier is required to be a string. Interpreting the contents of the string is currently left to the embedder effectively always making it a user defined module.

To circumnavigate this and preserving the current behavior a different ModuleSpecifier form using a special Identifier could be used instead of a string literal:

import { ... } from std.SomeStandardModule;

The std identifier is used to change the signature in a way that makes it possible for engines to detect this is a module that should be loaded from the standard library. The downside of using std.________ is that it start to look like a global object that is also available in other contexts.

It could also be possible to use specialized tokens in place of Identifier prefix, for example similar to C/C++:

import { ... } from <SomeStandardModule>;

While this makes importing standard library modules distinctly different from user defined modules this is also one of the downsides. The syntax is different from the import syntax developers should already be familiar with and a dynamic variant would be difficult (gramar wise).

Not using a prefix also has the downside of requiring everything from the standard library to live in the same space creating a new “global” namespace and preventing the use of multiple namespaces for different contexts.

Reference: tc39/ecma262#395-comment-371865432

Separate Keyword

When importing a module the ModuleSpecifier is required to be a string. Interpreting the contents of the string is currently left to the embedder effectively always making it a user defined module.

To circumnavigate this and preserving the current behavior a different keyword from import could be introduced specifically for importing modules from the standard library:

include { ... } from <SomeStandardModule>;

Important: The include keyword does not exist and is used for illustrative purposes only

The seperate keyword is emphasised by combining it with an Identifier for the ModuleSpecifier. The separate keyword already distingishes the module enough so we can also safely use a string literal for the ModuleSpecifier:

include { ... } from "SomeStandardModule";

While this makes importing standard library modules very distinctly different from user defined modules this is also one of its downsides. The syntax is different from the import syntax developers should already be familiar with and a dynamic variant of the keyword would also have to be created.

Not using a prefix also has the downside of requiring everything from the standard library to live in the same space creating a new “global” namespace and preventing the use of multiple namespaces for different contexts.

Reference: tc39/ecma262#395-comment-196917747

URL Based

There is already support for importing modules from a URL in browsers like Safari using import statements inside of a <script type="module" ... />. The host portion of the URL could be used as a prefix for distinguishing standard library modules and fits very natural within the concept of URLs:

import { ... } from "https://www.ecma-international.com/ecmascript/SomeStandardModule";

Using a URL with a domain for importing modules does not always make sense outside of a web context, for example in Node.js or embedded devices. It also requires ownership of the domain over a long period of time. A transfer of the domain might make the prefix useless or exclude a number of modules from being imported.

Reference: tc39/ecma262#395-comment-328528910

NPM Style

The Node Package Manager (NPM for short) has an established format for importing packages published to a central registry. The format allows packages to be grouped under organizations and this could be leveraged as a prefix for the JavaScript standard library:

import { ... } from "@std/SomeStandardModule";

While this format makes sense in environments where NPM is already used it is not as universal as a URL. The NPM style format also suffers some of the same downsides as a URL Based approach.

This format would require ownership over the organization on NPM (https://npmjs.com) and keeping multiple namespaces in mind would require all to do the same. But NPM is only the most commonly used registry, there might be other registries, possibly private ones that would be impossible to get ownership over a namespace. Using this format could exclude modules from being imported.

The biggest downside utilizing this format is standard library modules looking the same as user defined modules which might cause confusion, for example where modules come from in a Node.js/NPM context. The two modules behave different and the same assumptions can't be applied to both.

Reference: tc39/proposal-javascript-standard-library#16-comment-

Specification

Implementations

  • none yet

More Repositories

1

proposals

Tracking ECMAScript Proposals
17,177
star
2

ecma262

Status, process, and documents for ECMA-262
HTML
14,437
star
3

proposal-pipeline-operator

A proposal for adding a useful pipe operator to JavaScript.
HTML
7,534
star
4

proposal-pattern-matching

Pattern matching syntax for ECMAScript
HTML
5,498
star
5

proposal-optional-chaining

HTML
4,942
star
6

proposal-type-annotations

ECMAScript proposal for type syntax that is erased - Stage 1
JavaScript
4,252
star
7

proposal-signals

A proposal to add signals to JavaScript.
3,387
star
8

proposal-temporal

Provides standard objects and functions for working with dates and times.
HTML
3,321
star
9

proposal-observable

Observables for ECMAScript
JavaScript
3,058
star
10

proposal-decorators

Decorators for ES6 classes
2,640
star
11

proposal-record-tuple

ECMAScript proposal for the Record and Tuple value types. | Stage 2: it will change!
HTML
2,496
star
12

test262

Official ECMAScript Conformance Test Suite
JavaScript
2,073
star
13

proposal-dynamic-import

import() proposal for JavaScript
HTML
1,863
star
14

proposal-bind-operator

This-Binding Syntax for ECMAScript
1,742
star
15

proposal-class-fields

Orthogonally-informed combination of public and private fields proposals
HTML
1,722
star
16

proposal-async-await

Async/await for ECMAScript
HTML
1,578
star
17

proposal-object-rest-spread

Rest/Spread Properties for ECMAScript
HTML
1,493
star
18

proposal-shadowrealm

ECMAScript Proposal, specs, and reference implementation for Realms
HTML
1,429
star
19

proposal-iterator-helpers

Methods for working with iterators in ECMAScript
HTML
1,307
star
20

proposal-nullish-coalescing

Nullish coalescing proposal x ?? y
HTML
1,232
star
21

proposal-top-level-await

top-level `await` proposal for ECMAScript (stage 4)
HTML
1,083
star
22

proposal-partial-application

Proposal to add partial application to ECMAScript
HTML
1,002
star
23

proposal-do-expressions

Proposal for `do` expressions
HTML
990
star
24

proposal-binary-ast

Binary AST proposal for ECMAScript
961
star
25

agendas

TC39 meeting agendas
JavaScript
952
star
26

proposal-async-iteration

Asynchronous iteration for JavaScript
HTML
857
star
27

proposal-explicit-resource-management

ECMAScript Explicit Resource Management
JavaScript
746
star
28

proposal-set-methods

Proposal for new Set methods in JS
HTML
655
star
29

proposal-string-dedent

TC39 Proposal to remove common leading indentation from multiline template strings
HTML
614
star
30

proposal-operator-overloading

JavaScript
610
star
31

proposal-import-attributes

Proposal for syntax to import ES modules with assertions
HTML
591
star
32

proposal-async-context

Async Context for JavaScript
HTML
587
star
33

proposal-bigint

Arbitrary precision integers in JavaScript
HTML
561
star
34

ecmascript_simd

SIMD numeric type for EcmaScript
JavaScript
540
star
35

ecma402

Status, process, and documents for ECMA 402
HTML
529
star
36

proposal-slice-notation

HTML
523
star
37

proposal-change-array-by-copy

Provides additional methods on Array.prototype and TypedArray.prototype to enable changes on the array by returning a new copy of it with the change.
HTML
511
star
38

notes

TC39 meeting notes
JavaScript
496
star
39

proposal-class-public-fields

Stage 2 proposal for public class fields in ECMAScript
HTML
489
star
40

proposal-iterator.range

A proposal for ECMAScript to add a built-in Iterator.range()
HTML
483
star
41

proposal-decimal

Built-in exact decimal numbers for JavaScript
HTML
477
star
42

proposal-uuid

UUID proposal for ECMAScript (Stage 1)
JavaScript
463
star
43

proposal-module-expressions

HTML
433
star
44

proposal-throw-expressions

Proposal for ECMAScript 'throw' expressions
JavaScript
425
star
45

proposal-UnambiguousJavaScriptGrammar

413
star
46

proposal-weakrefs

WeakRefs
HTML
409
star
47

proposal-array-grouping

A proposal to make grouping of array items easier
HTML
407
star
48

proposal-error-cause

TC39 proposal for accumulating errors
HTML
380
star
49

proposal-cancelable-promises

Former home of the now-withdrawn cancelable promises proposal for JavaScript
Shell
376
star
50

proposal-ecmascript-sharedmem

Shared memory and atomics for ECMAscript
HTML
374
star
51

proposal-module-declarations

JavaScript Module Declarations
HTML
369
star
52

proposal-first-class-protocols

a proposal to bring protocol-based interfaces to ECMAScript users
352
star
53

proposal-relative-indexing-method

A TC39 proposal to add an .at() method to all the basic indexable classes (Array, String, TypedArray)
HTML
351
star
54

proposal-global

ECMAScript Proposal, specs, and reference implementation for `global`
HTML
346
star
55

proposal-private-methods

Private methods and getter/setters for ES6 classes
HTML
345
star
56

proposal-numeric-separator

A proposal to add numeric literal separators in JavaScript.
HTML
330
star
57

proposal-private-fields

A Private Fields Proposal for ECMAScript
HTML
319
star
58

tc39.github.io

Get involved in specifying JavaScript
HTML
318
star
59

proposal-object-from-entries

TC39 proposal for Object.fromEntries
HTML
318
star
60

proposal-promise-allSettled

ECMAScript Proposal, specs, and reference implementation for Promise.allSettled
HTML
314
star
61

proposal-await.ops

Introduce await.all / await.race / await.allSettled / await.any to simplify the usage of Promises
HTML
310
star
62

proposal-regex-escaping

Proposal for investigating RegExp escaping for the ECMAScript standard
JavaScript
309
star
63

proposal-export-default-from

Proposal to add `export v from "mod";` to ECMAScript.
HTML
306
star
64

proposal-logical-assignment

A proposal to combine Logical Operators and Assignment Expressions
HTML
302
star
65

proposal-promise-finally

ECMAScript Proposal, specs, and reference implementation for Promise.prototype.finally
HTML
279
star
66

proposal-json-modules

Proposal to import JSON files as modules
HTML
272
star
67

proposal-asset-references

Proposal to ECMAScript to add first-class location references relative to a module
270
star
68

proposal-cancellation

Proposal for a Cancellation API for ECMAScript
HTML
267
star
69

proposal-promise-with-resolvers

HTML
255
star
70

proposal-string-replaceall

ECMAScript proposal: String.prototype.replaceAll
HTML
253
star
71

proposal-export-ns-from

Proposal to add `export * as ns from "mod";` to ECMAScript.
HTML
242
star
72

proposal-structs

JavaScript Structs: Fixed Layout Objects
230
star
73

proposal-ses

Draft proposal for SES (Secure EcmaScript)
HTML
223
star
74

proposal-intl-relative-time

`Intl.RelativeTimeFormat` specification [draft]
HTML
215
star
75

proposal-json-parse-with-source

Proposal for extending JSON.parse to expose input source text.
HTML
214
star
76

proposal-flatMap

proposal for flatten and flatMap on arrays
HTML
214
star
77

proposal-defer-import-eval

A proposal for introducing a way to defer evaluate of a module
HTML
208
star
78

ecmarkup

An HTML superset/Markdown subset source format for ECMAScript and related specifications
TypeScript
201
star
79

proposal-promise-any

ECMAScript proposal: Promise.any
HTML
200
star
80

proposal-optional-chaining-assignment

`a?.b = c` proposal
186
star
81

proposal-decorators-previous

Decorators for ECMAScript
HTML
184
star
82

proposal-smart-pipelines

Old archived draft proposal for smart pipelines. Go to the new Hack-pipes proposal at js-choi/proposal-hack-pipes.
HTML
181
star
83

proposal-array-from-async

Draft specification for a proposed Array.fromAsync method in JavaScript.
HTML
178
star
84

proposal-upsert

ECMAScript Proposal, specs, and reference implementation for Map.prototype.upsert
HTML
176
star
85

proposal-collection-methods

HTML
171
star
86

proposal-array-filtering

A proposal to make filtering arrays easier
HTML
171
star
87

proposal-ptc-syntax

Discussion and specification for an explicit syntactic opt-in for Tail Calls.
HTML
169
star
88

proposal-extractors

Extractors for ECMAScript
JavaScript
166
star
89

proposal-error-stacks

ECMAScript Proposal, specs, and reference implementation for Error.prototype.stack / System.getStack
HTML
166
star
90

proposal-intl-duration-format

164
star
91

how-we-work

Documentation of how TC39 operates and how to participate
161
star
92

proposal-Array.prototype.includes

Spec, tests, reference implementation, and docs for ESnext-track Array.prototype.includes
HTML
157
star
93

proposal-promise-try

ECMAScript Proposal, specs, and reference implementation for Promise.try
HTML
154
star
94

proposal-extensions

Extensions proposal for ECMAScript
HTML
150
star
95

proposal-hashbang

#! for JS
HTML
148
star
96

proposal-import-meta

import.meta proposal for JavaScript
HTML
146
star
97

proposal-intl-segmenter

Unicode text segmentation for ECMAScript
HTML
146
star
98

proposal-resizablearraybuffer

Proposal for resizable array buffers
HTML
145
star
99

proposal-seeded-random

Proposal for an options argument to be added to JS's Math.random() function, and some options to start it with.
HTML
143
star
100

eshost

A uniform wrapper around a multitude of ECMAScript hosts. CLI: https://github.com/bterlson/eshost-cli
JavaScript
142
star