What the Heck is Node modules strict by default?
By: Brad
Hey Brad I’m working on a Node.js project and my team is using ESLint to statically analyze our code. I noticed that we are using the strict rule to ensure that we are not putting the use strict
pragma in our code files. I asked my team about it and they said that its because Node modules are strict by default now in Node v6 but I can’t find anything online confirming that. What the heck is Node modules strict by default or not?
I ran into the same rule when working with Node and did a bit of surfing around the information super highway to try and figure it out. I ran into this in the ECMAScript 2015 Standard
10.2.1 Strict Mode Code
An ECMAScript Script syntactic unit may be processed using either unrestricted or strict mode syntax and semantics. Code is interpreted as strict mode code in the following situations:
- Global code is strict mode code if it begins with a Directive Prologue that contains a Use Strict Directive (see 14.1.1).
- Module code is always strict mode code.
- All parts of a ClassDeclaration or a ClassExpression are strict mode code.
- Eval code is strict mode code if it begins with a Directive Prologue that contains a Use Strict Directive or if the call to eval is a direct eval (see 12.3.4.1) that is contained in strict mode code.
- Function code is strict mode code if the associated FunctionDeclaration, FunctionExpression, GeneratorDeclaration, GeneratorExpression, MethodDefinition, or ArrowFunction is contained in strict mode code or if the code that produces the value of the function’s [[ECMAScriptCode]] internal slot begins with a Directive Prologue that contains a Use Strict Directive.
- Function code that is supplied as the arguments to the built-in Function and Generator constructors is strict mode code if the last argument is a String that when processed is a FunctionBody that begins with a Directive Prologue that contains a Use Strict Directive.
ECMAScript code that is not strict mode code is called non-strict code.
It states that ES modules are strict by default but I was unclear as to if they were talking about CommonJS or ECMAScript nor what module system was used in Node v6 and if it was strict by default.
Rooting around I could not for the life of me find a straight answer to that question. There is lots of back and forth on forms but they all seemed to be about versions of Node before v4 and talked about using the --use-strict
flag to force all code into strict mode or just saying that ESLint was wrong and you should set the rule to require a global use strict
pragma in all your Node modules.
What I ended up doing was what any good developer does, I experimented.
I looked up what strict mode does and found that one of the things that it does is make the arguments
variable a local copy within the function vs. a reference.
Experiment Theory
In non-strict mode the arguments
variable which is accessible within any function and is an array like object containing all parameters passed into said function the parameters held within will be references to the same values stored in any named parameters in your function definition.
My meaning is that if we define a function which takes one parameter called myArg
I can reference it via myArg
but also by arguments[0]
. Therefore the act of changing the value of the parameter via the arguments
reference will change the value referenced by the named parameter myArg
.
function test(myArg) { console.log(`${myArg} -- ${arguments[0]}`); arguments[0] = 20; console.log(`${myArg} -- ${arguments[0]}`); } test(10);
If you execute the above in Node and we’re in non-strict mode it should print out:
10 -- 10
20 -- 20
If we were to run the code in strict mode however the arguments
array like object will contain a local copy of the values; thus modifying the value via the arguments
reference won’t effect the named parameter.
'use strict'; function test(myArg) { console.log(`${myArg} -- ${arguments[0]}`); arguments[0] = 20; console.log(`${myArg} -- ${arguments[0]}`); } test(10);
If you execute the above in Node and thanks to the pragma we are running in strict mode it should print out:
10 -- 10
10 -- 20
Experiment
To test if the Node module was being loaded in strict mode by default I ran this: $ node test.js
What I ended seeing printed out in my terminal was:
Local
10 -- 10
10 -- 20
Mod
10 -- 10
20 -- 20
Conclusion
Noticing that under Mod
the second line was changed to 20
meaning that when I changed arguments[0]
to 20
I modified my function’s named parameter thus arguments
is not a local copy and therefore my module is not in strict mode.
Node Modules are NOT strict by default.
I did re-run the experiment with --use-strict
and saw that both test.js and myModule.js were then in strict mode but you might not want to use the flag as it might break older npm packages that your project is depending on which rely on non-strict mode behaviour. That of course is a concern that I’m sure is dated and soon might not be an issue any more.
So what is with the standard saying modules are strict now?
Well the standard is talking about the new native modules in ECMAScript, ES Modules. These modules are imported and exported using the import
and export
keywords. Node is not using ES Modules yet; Node uses modules based on CommonJS, which are not strict by default. Its worth noting that you might be using the new import
/export
keywords today but its likely your using babel to transpile them back to Node Modules (i.e. require()
) so they are not actually ES Modules thus also not strict by default.
There you have it the answer to the question what the heck is Node modules strict by default. No, no they are not. At least not yet maybe one day Node will update to use ES modules but as of Node v6 and Node 8 Node modules are not strict by default.
Until next time think imaginatively and design creatively
Thx for the post, was using eslint ‘airbnb’ rules for a while and they told that modules are using ‘use strict’ by default and you do not need them, pulled the source code, and did not find any trace of ‘use strict injection there’
>but its likely your using babel to transpile them back to Node Modules (i.e. require()) so they are not actually ES Modules thus also not strict by default.
Actually Babel is pretty much aware about ES6 modules strict mode, moreover it assumes all files passed through it are ES6 modules by default and adds ‘use strict’ globally