TypeScript Version: [email protected]
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. https://github.com/Microsoft/TypeScript/issues/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.
but the file is a module? how are you using this file?
This file is not a npm module. It is loaded in browser on page load.
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?
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:
```package.json
"scripts": {
"compile": "tsc -p .",
"watch-ts": "tsc -p . --watch",
}
```tsconfig.json
{
"compilerOptions": {
"target": "es2015",
"module": "commonjs",
"sourceMap": true,
"removeComments": false,
"moduleResolution": "node",
"jsx": "react",
"pretty": true,
"outDir": "assemble/"
},
"include": [
"client/**/*"
],
"exclude": [
"node_modules"
]
}
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.
@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.
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.
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.
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.
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed.
Most helpful comment
Just _importing_ means it is a module. Whenever TypeScript sees the
importorexportkey word it assumes that you are declaring an ES6 module and will transpile it to your target module format. Usingconst foo = require('foo');is not importing in the eyes of the TypeScript compiler.