Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Upgrading from 1.2.0 to 1.3.0 breaks moment.js #418

Closed
Olian04 opened this issue Dec 27, 2017 · 15 comments
Closed

🐛 Upgrading from 1.2.0 to 1.3.0 breaks moment.js #418

Olian04 opened this issue Dec 27, 2017 · 15 comments

Comments

@Olian04
Copy link

Olian04 commented Dec 27, 2017

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
@brandon93s
Copy link
Contributor

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/

@brandon93s
Copy link
Contributor

brandon93s commented Dec 27, 2017

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

parcel/src/Resolver.js

Lines 50 to 58 in 0eb4487

// libraries like d3.js specifies node.js specific files in the "main" which breaks the build
// we use the "module" or "jsnext:main" field to get the full dependency tree if available
const main = [pkg.module, pkg['jsnext:main']].find(
entry => typeof entry === 'string'
);
if (main) {
pkg.main = main;
}

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

@Olian04
Copy link
Author

Olian04 commented Dec 27, 2017

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

@fathyb
Copy link
Contributor

fathyb commented Dec 27, 2017

@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 }; }

@Olian04
Copy link
Author

Olian04 commented Dec 29, 2017

@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?

@Olian04
Copy link
Author

Olian04 commented Dec 29, 2017

@brandon93s what exactly makes this a question? o_0

@fathyb
Copy link
Contributor

fathyb commented Dec 29, 2017

@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.

@brandon93s
Copy link
Contributor

@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.

@swyxio
Copy link

swyxio commented Jan 4, 2018

ah. so parcel doesnt work with typescript imports?

@gregorysl
Copy link

Any update on this one?

@robcrocombe
Copy link

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.

@fathyb
Copy link
Contributor

fathyb commented Jan 10, 2018

#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.

@trustyoo86
Copy link

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! 👍

@TimNZ
Copy link

TimNZ commented Mar 3, 2018

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.

@jdalton
Copy link

jdalton commented Mar 9, 2018

@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 🐛.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

10 participants