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

Undefined "exports" when nothing is exported #15795

Closed
Johnz86 opened this issue May 12, 2017 · 10 comments
Closed

Undefined "exports" when nothing is exported #15795

Johnz86 opened this issue May 12, 2017 · 10 comments
Labels
Needs More Info The issue still hasn't been fully clarified

Comments

@Johnz86
Copy link

Johnz86 commented May 12, 2017

TypeScript Version: typescript@2.3.2

Code

import { render } from "react-dom";
import * as React from "react";
import { initLocales } from "./gui/components/intl";

document.addEventListener("DOMContentLoaded", (event) => {
    initLocales(true);

    const [viewComponentName] = new URL(window.location.href).search.substr(1).split("&");
    const view = require(`./gui/views/${viewComponentName}`).default;
    render(React.createElement(view, null), document.getElementById("appcontainer"));

});

Expected behavior:

"use strict";
const react_dom_1 = require("react-dom");
const React = require("react");
const intl_1 = require("./gui/components/intl");
document.addEventListener("DOMContentLoaded", (event) => {
    intl_1.initLocales(true);
    const [viewComponentName] = new URL(window.location.href).search.substr(1).split("&");
    const view = require(`./gui/views/${viewComponentName}`).default;
    react_dom_1.render(React.createElement(view, null), document.getElementById("appcontainer"));
});

Actual behavior:

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const react_dom_1 = require("react-dom");
const React = require("react");
const intl_1 = require("./gui/components/intl");
document.addEventListener("DOMContentLoaded", (event) => {
    intl_1.initLocales(true);
    const [viewComponentName] = new URL(window.location.href).search.substr(1).split("&");
    const view = require(`./gui/views/${viewComponentName}`).default;
    react_dom_1.render(React.createElement(view, null), document.getElementById("appcontainer"));
});

This is a recurrnig issue. #14351
I reported this previously.
After compilation appears

Object.defineProperty(exports, "__esModule", { value: true });

and the result is "Uncaught ReferenceError: exports is not defined.

Ther is no actual module exported in the file. If I manually remove this piece of code everything works fine.

@mhegazy
Copy link
Contributor

mhegazy commented May 12, 2017

but the file is a module? how are you using this file?

@mhegazy mhegazy added the Needs More Info The issue still hasn't been fully clarified label May 12, 2017
@Johnz86
Copy link
Author

Johnz86 commented May 15, 2017

This file is not a npm module. It is loaded in browser on page load.

@kitsonk
Copy link
Contributor

kitsonk commented May 15, 2017

require() does not work out of the box on a browser page. Whether you like it or not, you are writing a CommonJS module. Are you using Browserify or WebPack to transform that CommonJS Module into something that can work in a browser? If not, why not? How did you expect it to work?

@Johnz86
Copy link
Author

Johnz86 commented May 15, 2017

Require has nothing to do with this problem. If I delete the line with "exports" manually after compilation everything works.

I am using typescript version 2.1.4. Which still works for me and does not produce "exports", when there is no module exported.

We do not use webpack or any other module bundler. We have an existing electron project, which compiles with:

 "scripts": {
    "compile": "tsc -p .",
    "watch-ts": "tsc -p . --watch",
}
{
    "compilerOptions": {
        "target": "es2015",
        "module": "commonjs",
        "sourceMap": true,
        "removeComments": false,
        "moduleResolution": "node",
        "jsx": "react",
        "pretty": true,
        "outDir": "assemble/"
    },
    "include": [
        "client/**/*"
    ],
    "exclude": [
        "node_modules"
    ]
}

@kitsonk
Copy link
Contributor

kitsonk commented May 15, 2017

Ah, Electron provides require() in the browser. That is the context that was missing to properly identify the issue.

I am not sure what Mohamed's take on it will be, but this seems to fall into one person's regression is another person's feature. You are clearly instructing TypeScript to generate CommonJS modules. It is ensuring that it is emitting a module that fully complies with what is expected for a down-emitted CommonJS module so that loaders can differentiate on how to load it. Therefore because it is expecting to load by a CommonJS loader (like Node.js's require()) part of that specification is that exports is available in the scope of the module. So what TypeScript is doing is technically valid. In addition, it also appears on your Electron environment you have turned off nodeIntegration in the browser, otherwise exports would be available when the module is loaded.

@Johnz86
Copy link
Author

Johnz86 commented May 15, 2017

@kitsonk we have the node integration turned on. You are right Typescript uses commonjs for module resolution. What I do not get is, why would you expect that "exports" is defined, when you are not specifing a module, just importing stuff.

@kitsonk
Copy link
Contributor

kitsonk commented May 15, 2017

Just importing means it is a module. Whenever TypeScript sees the import or export key word it assumes that you are declaring an ES6 module and will transpile it to your target module format. Using const foo = require('foo'); is not importing in the eyes of the TypeScript compiler.

@lal12
Copy link

lal12 commented May 16, 2017

Hmm I see that typescript expects exports as variable in such an environment. But with e.g. "module":"amd" it also checks for existence of module.exports, but then accesses exports. While nwjs defines module.exports it does not define exports. I guess electron behaves similar.


 if (typeof module === "object" && typeof module.exports === "object") {
        var v = factory(require, exports);
        if (v !== undefined) module.exports = v;
    }
    else if (typeof define === "function" && define.amd) {
        define(["require", "exports", "jquery"], factory);
    }

Just checking for typeof exports === "object" too, would help.
Or at least adding some kind of option for usage in electron and nwjs

So the solution for "commonjs" should be to check if exports exists or using module.exports instead.

@lal12
Copy link

lal12 commented May 16, 2017

I am now using a workaround:
I wrote an intermediate js file just containing require('main.js'). The main.js contains the transpiled ts code and there the exports object is available.

@mhegazy
Copy link
Contributor

mhegazy commented May 30, 2017

Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.

@mhegazy mhegazy closed this as completed May 30, 2017
@microsoft microsoft locked and limited conversation to collaborators Jun 14, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Needs More Info The issue still hasn't been fully clarified
Projects
None yet
Development

No branches or pull requests

4 participants