Parcel: 馃悰 Upgrading from 1.2.0 to 1.3.0 breaks moment.js

Created on 27 Dec 2017  路  15Comments  路  Source: parcel-bundler/parcel

I'm using typescript and when i upgrade parcel from 1.2.0 to 1.3.1 _(I've tried with 1.3.0 as well)_ the moment.js library starts complaining about moment not being a function.

馃帥 Configuration (.babelrc, package.json, cli command)

// package.json
{
  "scripts": {
    "start": "parcel index.html --out-dir temp/"
  },
  "dependencies": {
    "moment": "^2.20.1",
    "parcel-bundler": "1.3.0",
    "typescript": "^2.6.2"
  }
}
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <title>Document</title>
</head>
<body>
    <script src="./app.ts"></script>
</body>
</html>
//app.ts
import * as moment from 'moment';

console.log( moment() );

_No tsconfig.json_

馃 Expected Behavior

I would expect a moment object to be printed to the console.

馃槸 Current Behavior

With parcel v1.2.0 the moment object is printed just fine. But with parcel v1.3.0 or v1.3.1 it throws a TypeError.

b6623a1acd83678d58392c21229a4b42.js:6473 Uncaught TypeError: moment is not a function
    at Object.require.2.moment (b6623a1acd83678d58392c21229a4b42.js:6473)
    at newRequire (b6623a1acd83678d58392c21229a4b42.js:41)
    at require.4 (b6623a1acd83678d58392c21229a4b42.js:66)
    at b6623a1acd83678d58392c21229a4b42.js:71

馃敠 Context

Gist of all files used to recreate bug: https://gist.github.com/Olian04/ce4e23c11a17d60c9a39247a879e54c7

馃實 Your Environment

| Software | Version(s) |
| ---------------- | ---------- |
| Parcel | 1.2.0 & 1.3.0 & 1.3.1
| Node | 9.3.0
| npm/Yarn | 5.5.1 / 1.3.2 _(I've tried with both)_
| Operating System | Ubuntu 17.04

Bug Help Wanted

Most helpful comment

I'm also using typescript in my projects now. I have experienced the same error as yours, Typescript is upgraded to version 2.7, it supports es6 module. so I solved the same problem as yours, try version up for typescript, and add tsconfig.json

{
 "esModuleInterop": true
}

I solved moment js problem. try this! 馃憤

All 15 comments

Unsure yet exactly why the default behavior has changed, but the following is a workaround:

// change this
import * as moment from 'moment';

// to this
import moment from 'moment';

OR

// change this
console.log ( moment() );

// to this
console.log( moment.default() ); 

https://momentjs.com/docs/#/use-it/typescript/

The addition of the following lines resulted in the "breaking change". Commenting them out in master restores previous functionality:

https://github.com/parcel-bundler/parcel/blob/0eb4487491fd70390697ad413aeac994fca4309c/src/Resolver.js#L50-L58

Original: #298
PR: #299
Follow-up: #359

@fathyb @devongovett

For reference, moment's package.json:

"main": "./moment.js",
"jsnext:main": "./src/moment.js",

./moment.js
./src/moment.js

@brandon93s
import moment from 'moment'; isn't valid ts, since moment doesn't provide a default export.

@Olian04 ~moment is exported as default in it's ES6 form, see the code (referenced by jsnext:main). The problem here is that the main field points to a UMD module, which uses module.exports.~

edit: Didn't understood you were talking about ts. Yeah allowSyntheticDefaultImports is the way to go. Parcel uses Babel which will automatically find if a module is ES6 or CommonJS and export the correct value accordingly, so it's safe to use :

var _moment = require("moment");

var _moment2 = _interopRequireDefault(_moment);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

@fathyb yea, parcel users Babel for js files. But it uses tsc for ts files. So I'm not really sure how referring to Babel is relevant. Or am I missing something?

@brandon93s what exactly makes this a question? o_0

@Olian04 TypeScript sources are treated like any JavaScript files once they are processed. If you use "module": "es6" your import declarations are transformed by Babel to require calls with default interoperability like described above.

@Olian04 - mostly a parcel team question to spawn discussion on how to handle this. The change that lead to this behavior is valid, and consumers can get past it with appropriate imports. However, it won't be compatible in many cases with existing code so we'll need to determine a path forward for handling it.

ah. so parcel doesnt work with typescript imports?

Any update on this one?

This is also breaking my project. I need import moment from 'moment'; for Parcel, but import * as moment from 'moment'; for running tests (which compile from TS directly). Any help would be appreciated.

530 has been created to fix this and has been tested with moment. I encourage you to try it while it's being reviewed as it changes how Parcel interpret import * as.

I'm also using typescript in my projects now. I have experienced the same error as yours, Typescript is upgraded to version 2.7, it supports es6 module. so I solved the same problem as yours, try version up for typescript, and add tsconfig.json

{
 "esModuleInterop": true
}

I solved moment js problem. try this! 馃憤

I've tried to use two react date UI packages that require('moment') and are broken by the es6'fying of the returned moment object (if I understand the issue correctly) by Parcel/Babel
i.e. { default: moment, __esModule: true }

What exactly is happening, and is there anything I can do now to stop that happening? Such as a .babelrc option?

Not using typescript.

Not realistic to have to create forks of packages that then use moment to work around this.

@Olian04

I would expect a moment object to be printed to the console.

Your expectation is incorrect. If it worked in previous versions of parcel then that was a 馃悰.

Was this page helpful?
0 / 5 - 0 ratings