I'm using Typescript, ES6 module syntax, and SystemJS / builder.
The basic requirements I'm trying to do are:
- Enable typescript code completion by using @types packages (for global npm installs as well)
- Using ES6 module import syntax (e.g.
import * as _ from 'lodash'
) - Have the builder exclude the globals from the build and still have them properly imported using CDN urls in dev / production.
The config I'm using for the build and dev / production env just to get it up and going:
System.config({
meta: {
"lodash": {
"format": "global",
"build": false,
"exports": "_"
}
// ...more meta
},
map: {
"lodash": "https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.13.1/lodash.min.js",
// ...more maps
}
});
From here I have a npm task which transpiles to ES6 and then bundles everything into a single file through babel plugin. The script is loaded directly on the production page fine and it loads. The issue is once a global dependency imports I keep getting errors like "_.clone is not a function" etc due to systemjs wrapping the CDN imports with an object like
{default: _ } //_ is the actual lodash export
I've been successful in changing the import to import _ from 'lodash'
but then I get IDE errors since lodash (nor any other global script like angular) does not export a default value and I lose code completion.
What's the correct way to meet the requirements with systemjs / builder here?
As a side note I'm fine with using script tag loading instead of systemjs CDN imports if that works better.
TypeScript has a flag
--allowSyntheticDefaultImports
for just this scenario. Specifically, it informs the typechecker that another transpiler, loader, or bundler provides mapsmodule.exports
toexports.default
in a later step.You can specify this flag in under compiler options in tsconfig.json
Note that when the module format is set to
"system"
, this flag is set implicitly.Now you can write
and TypeScript will understand it, typecheck it, and validate that it is used correctly. However, this only affects typechecking. You still need, and in this case already have, a loader or intermediate transpiler that provides the runtime synthesis.
violates the proposed NodeJS -> ESM interop proposal and, if you call it as in
_([1, 2]).map(x => x ** 2)
also violates the ES spec which forbids a Module Namespace Object from being callable., so you are doing well to take advantage of the--allowSyntheticDefaultImports
flag and the interop provided by SystemJS.