vscode dynamic es6 module import error - javascript

vscode does not seems to support es6 import when used as a function to load dynamic chucks.
import is actually supported by webpack 2 + babel.
There are no issue with normal es6 imports or when using async functions.
Eslint was also reporting an error until I integrated babel-eslint.
I am using vscode version 1.9.1
I tried using a jsconfig.json but it did not change anything
{
// See http://go.microsoft.com/fwlink/?LinkId=759670
// for the documentation about the jsconfig.json format
"compilerOptions": {
"target": "es2017"
},
"exclude": [
"node_modules",
"bower_components",
"jspm_packages",
"tmp",
"temp"
]
}

I don't think dynamic imports are part of ES6, and they aren't supported by TypeScript yet (which drives the JS language service) so I think you'll have to use require.

You can set "javascript.validate.enable": false in the preferences and use another syntax validation (for example https://github.com/flowtype/flow-for-vscode).

Dynamic imports are now supported by TypeScript (v2.4.x) and VSCode since June 2017 release (v1.14.x).

Related

How can I use "exports" in package.json today for nested submodules and typescript

Latest Update (2022-06-06): TS 4.7 supports "exports"
tl;dr
// package.json
"type": "module"
// tsconfig.json
"module": "node12" // or "nodenext"
Update: TS 4.5 does not support "exports" (also see this issue):
... support for Node.js 12 has been deferred to a future release, and is now only available as an experimental flag in nightly releases. This was not an easy decision, but our team had a combination of concerns around ecosystem readiness and general guidance for how/when to use the feature.
[2022-04-01] The feature is still not available in TS 4.6.
Original question:
I am wanting to take advantage of the new-ish "exports" feature of NodeJS/package.json so that I can do the following:
"exports": {
".": "./dist/index.js",
"./foo": "./dist/path/to/foo.js"
}
And users can do the following:
import { foo } from 'my-package/foo';
Typescript 4.5 should support the "exports" field, yet it does not seem to work. I am building a simple package using TS 4.5.2, and I am consuming that package in a project using TS 4.5.2. I have looked at other SO questions and this github thread and this bug report but can't seem to find a consensus on the issue and whether it should work today.
Note 1: I am still able to import using the more verbose syntax:
import { foo } from 'my-package/dist/path/to/foo.js';
Note 2: I have also tried the object notation for exports, to no avail:
"exports": {
".": { "require": "./dist/index.js", "import": "./dist/index.js" },
"./foo": { "require": "./dist/path/to/foo.js", "import": "./dist/path/to/foo.js" }
}
Question(s):
Is this feature ready to be used with typescript projects today? If not, I just want to know.
If yes to #1, what am I missing? Specifics about tsconfig would be useful for both the source project and consuming project. The TS compiler complains about node12/nodenext being used for either the module or moduleResolution fields (I am definitely using TS 4.5.2).
I've been looking to use nested folders for a design system package we created at Pipefy, and after deep research, I found how to do it.
The package exports React components, and we use to import them like this import { Button } from '#mypackage/design-system;
Later on, we've added tokens to our design system library, like Colors, Spacing, and Fonts, but we don't want to import everything from the index, it isn't productive.
After some exhaustive research, I found how to export nested folders using TypeScript. My purpose is to use tokens like this import { Colors } from '#mypackage/design-system/tokens;
To use your TypeScript lib like this you should use the typesVersions inside the package.json file.
Here I use it like this
"typesVersions": {
"*": {
"index": [
"lib/components/index.d.ts"
],
"tokens": [
"lib/tokens/index.d.ts"
]
}
},
It worked like a charm for me, it would work for you too!
Without knowing what error you are getting, or in what other way TypeScript doesn't seem to be working for you (not sure why you would not want to share such crucial information), I can tell that your exports section appears to be missing types information. Typically, if your .d.ts files were located next to their respective .js files, your exports section would look like this:
"exports": {
".": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"./foo": {
"types": "./dist/path/to/foo.d.ts",
"default": "./dist/path/to/foo.js"
}
}
I'm posting my own answer because there has been a lot of confusion around this topic.
NodeJS has supported exports since v12.7.0 (Jul. 2019)
When I asked this question (Dec. 2021), NodeJS had supported the exports field for nearly 2.5 years. It seemed reasonable to assume that Typescript supported it.
Typescript did not support the exports field when I asked this question.
When I asked this question (Dec. 2021), the exports field in package.json was not supported by the current version of Typescript at the time (v4.5). This was particularly confusing because the TS 4.5 beta announcement said that it would support the package.json exports.
Typescript 4.7 (Jun. 2022) finally supported package.json exports
After much testing and quite a bit of secrecy, typescript finally supported the exports field for package.json. Wine and whiskey were consumed with this announcement.
Using typesVersions in package.json is not the solution
Several people suggested using typesVersions - but thats a completely separate feature which is specific to typescript only (read more about it here). The exports field in package.json is supported by ANY npm package - typescript or not.
What you need in order for this to work
Your typescript project must be using TS v4.7 or later
Your tsconfig should be using moduleResolution: node, node16, or nodenext.
You don't have to set moduleResultion if you are using module with a value of CommonJS, ES2015, ES6, ES2020, or ESNEXT
TypeScript only respects export maps in package.json if you use "moduleResolution": "NodeNext"(or "Node16") instead of the widespread "moduleResolution": "Node". (I guess "moduleResolution" defaults to the same value as "module", but it's hard to find documentation of this?
See: https://www.typescriptlang.org/docs/handbook/esm-node.html
However a number of TS libraries out there (including many of Microsoft's own) have errors with "moduleResolution": "NodeNext" right now because of things like relative imports without explicit file extensions.

Using native ECMAScript modules in Babeljs config

I'm very, very confused about using babel config with native ECMAScript modules, and "type": "module" set in package.json. As far as I understand Babel docs (here, under "Supported file extensions"), its should be possible. But if I try with config like this:
const config = () => {
const presets = [
"#babel/preset-react",
[
"#babel/preset-env",
{
bugfixes: true,
useBuiltIns: "usage",
corejs: { version: "3.6", proposals: true },
},
],
];
const plugins = ["#babel/plugin-transform-runtime"];
return { presets, plugins };
};
export default config;
I get Error while loading config - You appear to be using a native ECMAScript module configuration file, which is only supported when running Babel asynchronously.
This is expected as the said docs states that "native ECMAScript modules are asynchronous". Alas, sprinkling the above config with async / await doesn't solve the problem. I'm running babel through parcel - is this a issue with parcel? Did I misunderstood the docs? I really appreciate if someone could clarify it for me.
I had a similar problem, and reading Babel site, I came to conclusion that whatever is using your babel config is not calling it asynchronously. In my case it was jest 26.
I got around the problem by changing the config to a json file - babel.config.json.
Other people have changed their config file to a commonjs file - babel.config.cjs, then you will need to change your config file to be commonjs, i.e. to use module.exports = {rest of your config}
I think the problem is that your package.json says you are using ES6 modules, but your Babel config is using module.exports which is CommonJS (not ES6 modules).
Rename babel.config.js to babel.config.cjs

Do Any JavaScript Test Frameworks Support ES Modules

Do any test frameworks support tests that use the new ES Modules syntax? I have a JS application which heavily uses .mjs files with ES Modules. I tried Jest and Jasmine, both of which throw errors when I try to write run tests for my app. I need to test this file:
math.mjs
export function add(a, b) {
return a + b;
}
As of February 2022, this is what I saw:
Jasmine: built-in support.
Jest: built-in experimental support, requires configuration to code transformations and a node flag.
Mocha: built-in experimental support lacks some features such as watch mode.
Tape: built-in support (not mentioned in docs).
AVA: built-in support (not mentioned in released docs, but there's a recent commit to the docs switching all examples to esm)
UVU: built-in support explicitly mentioned in the docs
Other test runners with support for ES Modules are:
AVA: AVA 4 explicitly mentions ESM, but I've also used AVA 3 with ES modules without problems
UVU: A lightweight test runner that supports ES Modules and does not pull tons of dependencies into the project
You can use the esm package with Jasmine. Not sure about Jest though 🤔
math.spec.js
import { add } from './math.mjs';
describe('Add', () => {
it('should add 3 and 2', () => {
expect(add(3,2)).toBe(5);
});
});
Install and run
$ yarn global add jasmine esm
$ jasmine --require=esm
Randomized with seed 44366
Started
.
1 spec, 0 failures
Finished in 0.004 seconds
I tried Vitest and it worked like a charm. My goal was to build a publishable library with typescript. The library was part of a monorepo built with Nxw with "type": "module" in package.json and the following in my tsconfig.json:
"compilerOptions": {
"module": "ESNext",
"target": "ES6",
"moduleResolution": "node"
}
It worked with 0 configuration, and I tried testing functions that used both CJS and ESM type imports from 3rd party packages.
On a side note, I really like the clean syntax. Plus, vitest also supports testing components built with React/Vue.
The project Japa works with ESM and Typescript, and works perfectly in my set-up (Node.js 16.x with "type": "module" and .js files). The only issue I got was easy to solve, so you should give it a try

What does the "target" property in tsconfig.json actually represent?

I have been developing an Angular app using Typescript, and I have come to realise I need to pay more attention to the tsconfig in regards to compilation (transpilation).
Currently in the source code I am using some es6 features (such as Array.prototype.find) and the TSLint-er is picking up these as errors.
I'm trying to reconfigure my tsconfig so that it allows me to use es6 features but transpile to es5. In doing this, I'm failing to understand what the "target" property actually is. What does the "target" property mean?
Does "target" represent what the desired, transpiled output will be? Or does it declare what the Typescript syntax should conform to in order to be transpiled?
TypeScript is a superset of ES6, so you’re essentially writing TS code using ES6 version of JavaScript. However, when compiled, the resulting JS code can be in ES5 or earlier. You need to define which version of JS the compiler should transpile into. This can be set using target option:
{
"compilerOptions": {
"target": "es6"
}
}
You can read more about configuration here.
However, it also is used for validation indirectly. This parameter defines which libraries are used during compilation. If you specify target:es5, it uses ES5 library which doesn't contain Array.prototype.find. You can manually set the library you want to be used:
{
"compilerOptions": {
"lib": ["es6", "dom"],
}
}
In this case you will not have an error even if you specify es5 as a target.

Babel / Rollup errors transpiling and bundling ES2017

I'm getting an error transpiling ES2017 JavaScript (specifically async/await functions) into ES5 using Rollup and Babel:
Error transforming \src\index.js with 'babel' plugin: Options
{"modules":false} passed to
\node_modules\babel-preset-es2017\lib\index.js which does not accept
options.
My .babelrc file:
{
"presets": [
"es2017"
],
"plugins": [
"transform-runtime"
],
"comments": false
}
Naturally, the error goes away if I change the presets from es2017 to es2015 and comment out the async/await code.
Note that while the application uses ES2017 features (i.e. async/await), it is published as an NPM package (as an ES6 (ES2015) module) that is later transpiled to generic ES5 (ES2009).
How do I get past this error and get my ES2017 happily transpiling to ES5?
It seems that the actual configuration you provided is:
{
"presets": [
"es2017", {modules: false}
],
"plugins": [
"transform-runtime"
],
"comments": false
}
You should remove the {modules: false} option for babel-preset-es2017, which accepts none, as it applies to babel-preset-es2015.
Target es2015 in your .babelrc file:
"presets": [
"es2015"
],
and preprocess the es2017 features by first adding the Rollup Async functions plugin, which:
replaces async functions with generator functions that can run in
modern browsers or in most versions of node.js during bundling
Add to your project:
npm install --save-dev rollup-plugin-async
And then insert async preprocessing to your rollup.config.js plugins array, before babel():
import async from 'rollup-plugin-async';
...
plugins: [
async(),
babel(babelrc())
],
The key insight was found in this Rollup Github issues thread, wherein #Victorystick confirms that (as of Oct 10, 2016):
Rollup currently only targets ES6, although it'll likely get extended
to ES7 shortly. For now, if you use >ES6 features, they'll need to be
transpiled for Rollup to process them
As async/await are likely to be standardized in the next version of ECMAScript, ES2017 (aka ES8), you'll need an extra plugin to process them before Babel runs.
NOTE:
YMMV, but I later received AsyncHelper not found run time Errors using rollup-plugin-async on Windows 7, so my solution was to (npm uninstall --save-dev rollup-plugin-async and) rollback use of async/await in favor of ES6 Promises throughout my codebase.

Categories