systemjs: SystemJS@0.20 incompatible with TypeScript
It seems like newModule() does not work well with CommonJS module that exports a function.
Sample code:
const lowercase = require('lower-case') // lowercase is a function
// configuration skipped for simplicity
SystemJS.set('lower-case', SystemJS.newModule(lowercase))
SystemJS.import('my-module')
// my-module/index.js
var lowercase = require('lower-case')
console.log(lowercase) // prints `{ }`
module.exports = lowercase('my-module')
Is there a way to solve this? This is for the plugin system I’m working on. The config is similar to: https://github.com/unional/some-issues/blob/systemjs-jsdomify/src/createSystemJS.ts
About this issue
- Original URL
- State: closed
- Created 7 years ago
- Reactions: 8
- Comments: 26 (14 by maintainers)
My Angular2/TypeScript project fails when using SystemJS 0.20.x:
Unhandled Promise rejection: core_1.OpaqueToken is not a constructorAs soon as I go back to 0.19.x it’s ok, again.
Ok, this is a much bigger issue. The way
systemjs@0.20handles commonjs code is not the same way as how TypeScript handles commonjs code.My understanding is that
systemjs@0.20follows babel and NodeJS to import commonjs in thedefaultproperty. However, TypeScript does not. In TypeScript,This is related to https://github.com/Microsoft/TypeScript/issues/7398 https://github.com/Microsoft/TypeScript/issues/8687
And it is a serious problem. AFAIK, there is no good solution (
allowSyntheticDefaultImportswouldn’t work due to https://github.com/Microsoft/TypeScript/issues/7398).I use SystemJS 0.19.x until this issue is fixed.
That sounds just like the government debt and GDP issue, but that would be way way off topic. 😛
IMO, TypeScript way provides a better mapping for CommonJS,
import * as X from 'X'should receive an immutable namespace object and that maps more naturally tomodule.exports = ....Moving things and adding
{ default: ... }seems artificial.TypeScript team and community should be more active to discuss and work with NodeJS and WHATWG, to help driving TS/JS to unity. 😞
@unional
Indeed, from what I understand, there is serious mental dissonance on the issue. While I could be mistaken about this, I believe it stems from a few TypeScript specific factors.
For one TypeScript has directly supported CommonJS modules for much longer than it has supported ES Modules. Consider the
syntax that TypeScript has long supported. While this is just syntactic sugar to obtain both types and values from a
require, it unsurprisingly desugars intoI think that this is relevant because TypeScript seems to have a radically different conception of what CommonJS is as a module format.
From the Babel point of view, CommonJS is a legacy module format, something to which a direct transliteration (regardless of viability) is not even sought after.
On the other hand, from the TypeScript point of view, CommonJS is a first class module format. Furthermore, TypeScript allows mixing all forms of module syntax together under
"module": "commonjs". I think this is a major issue. It does not seem to consider CommonJS a legacy format at all and rather just transliterates the ES Module syntax directly into property assignments on theexportsobject. It also does things like emit multiplerequires, causing aliasing issues when the same module is imported circularly and or multiple times. It does both of these as a matter of course because it is not trying to perform any semantic mapping when targeting CommonJS with ES Module syntax.Some recent TypeScript issues that I believe are relevant are https://github.com/Microsoft/TypeScript/issues/12522 https://github.com/Microsoft/TypeScript/issues/13245
@guybedford I’ve added the config you provided but now I’m getting this error instead:
typescript is not a valid transpiler plugin.Thanks for pointing to the link.
Slightly off topic, regarding: https://github.com/nodejs/node-eps/blob/master/002-es6-modules.md#571-es-will-not-honor-reassigning-moduleexports-after-evaluation
Isn’t that the exact behavior of this issue? https://github.com/Microsoft/TypeScript/issues/12522
For
set(), I can get around it by using an internal flag__useDefault:@guybedford what should be the direction to fix this? can we introduce
SystemJS.newCJSModule()? Or insidenewModule()do this wrapping when__esModule !== true?UPDATE: seems like this will cause other tests to break. What should go into
this.registry? Immutable module object/namespace? I guess that’s what theModuleNamespaceis about.However, I don’t know what should it be for CJS.
Maybe: