Home > Blockchain >  Are Immutable ECMAScript Modules Speced Behavior?
Are Immutable ECMAScript Modules Speced Behavior?

Time:08-04

Javascript, somewhat infamously, allows your entire program to modify any object. In Node.js this means you can modify a CommonJS module at runtime. If you have a program like this

// File: change-it.js
const express = require('express')
express.myProp = 'hello world'

// File: index.js
require('./change-it')
const express = require('express')
console.log(express.myProp)

and run it, you'll get the following output.

% node index.js
hello world

That is, we've successfully added a property to the express module.

However, the new native ECMAScript modules (also know as ESM modules -- the ones that use import) do not apear to support this behavior. In fact, Node.js outright rejects it.

That is, a program like this

// File: index.mjs
import * as a from './a.mjs'
import * as b from './b.mjs'
console.log(a)
console.log(b)

// File: a.mjs
import * as b from './a.mjs'
b.myProp = 'hijacked!'
export const a = 'hello world'

// File: b.mjs
export const b = 'goodbye world'

Will error out with the following error

% node index.mjs
file:///path/to/a.mjs:2
b.myProp = 'hijacked!'
         ^

TypeError: Cannot add property myProp, object is not extensible
    at file:///path/to/a.mjs:2:10
    at ModuleJob.run (node:internal/modules/esm/module_job:198:25)
    at async Promise.all (index 0)
    at async ESMLoader.import (node:internal/modules/esm/loader:385:24)
    at async loadESM (node:internal/process/esm_loader:88:5)
    at async handleMainPromise (node:internal/modules/run_main:61:12)

My Question: Is this speced behavior of ECMAScript modules, or is this a choice the Node.js developers made? If speced is there a section (or sections?) of the ECMAScript that covers expectations here?

(I've tried looking at the ECMAScript spec and I'm afraid I don't speak whatever dialect of engineering english the smart folks who put that together do)

CodePudding user response:

Yes, module namespaces - for example, the a after the line:

import * as a from './a.mjs'

cannot be mutated. Its IsExtensible property is:

The [[IsExtensible]] internal method of a module namespace exotic object takes no arguments and returns a normal completion containing false. It performs the following steps when called:

  1. Return false.

Only extensible objects can have properties added to them.

  • Related