frankwallis / plugin-typescript

TypeScript loader for SystemJS
MIT License
248 stars 47 forks source link

exports is not defined #202

Open MoonStorm opened 7 years ago

MoonStorm commented 7 years ago

After posting this bug on several projects, I ended up posting it in here. I am trying to import HTML templates in typescript while using the text plugin. Typescript is set to generate commonjs modules and target es5 and the text plugin produces es modules. In this configuration, the bundle generated by the jspm bundle looks like this:

System.register("app/components/component.html", [], function (_export, _context) {
  "use strict";
  return {
    setters: [],
    execute: function () {
      Object.defineProperty(exports, "__esModule", { value: true });
      exports.__useDefault = true;
      exports.default = "<div>....</div>";
    }
  };
});

Using this bundle in the browser produces the error exports is not defined.

Aligning the text plugin to generate cjs modules

'use strict';
module.exports = {
    translate: function (load) {
        load.metadata.format = 'cjs';
        var output =
        'module.exports = function () {' +
        '       return module.exports["default"].apply(this, arguments);' +
        '};'+
        'Object.defineProperty(module.exports, "default", {value: '+JSON.stringify(load.source)+'});';

        return output;
    }
}

fixes this problem and the bundle looks like this:

System.registerDynamic("app/components/component.html", [], true, function ($__require, exports, module) {
  var global = this || self,
      GLOBAL = global;
  module.exports = function () {
    return module.exports["default"].apply(this, arguments);
  };
Object.defineProperty(module.exports, "default", { value: "<div>...</div>" });
});

The issue has been discussed a little bit in here, with @guybedford and @aluanhaddad trying to get to the bottom of it.

Any help would be appreciated. Thanks.

aluanhaddad commented 7 years ago

EDIT: created repo https://github.com/aluanhaddad/plugin-text-plugin-typescript-issue-x

For reference, I was able to reproduce the specific error encountered by @MoonStorm but becoming perplexed with trying to find the root cause, I tried a number of different scenarios, including issues which break usage when transpiling to supported formats.

For my tests I used the following setup

SystemJS: 0.20.10 jspm: 0.17.0-beta.41 plugin-typescript: 7.0.5 plugin-text: 0.0.9 typescript: 2.2.2

Files

index.html

<!DOCTYPE html>
<html lang="en">
<body>
  <script src="jspm_packages/system.js"></script>
  <script src="jspm.config.js"></script>
  <script>
    SystemJS.import('app').then(app => app.default()).catch(console.error);
  </script>
</body>
</html>

src/main.ts

import template from './template.html';

export default function () {
  console.log(template);
}

src/template.html

<div>Hello</div>

jspm.config.js (dependency config elided but standard)

SystemJS.config({
  paths: {
    "github:": "jspm_packages/github/",
    "npm:": "jspm_packages/npm/",
    "app/": "src/"
  },
  transpiler: "plugin-typescript",
  sourceMap: true,
  typescriptOptions: {
    "tsconfig": "tsconfig.{format}.json" // see below
  },
  packages: {
    "app": {
      "main": "main.ts",
      "defaultExtension": "ts",
      "meta": {
        "*.ts": {
          "loader": "plugin-typescript"
        },
        "*.html": {
          "loader": "text"
        }
      }
    }
  }
});

tsconfig.es2015.json

{ "compilerOptions": { "module": "es2015", "target": "es5"  } }

tsconfig.system.json

{ "compilerOptions": { "module": "system", "target": "es5"  } }

tsconfig.amd.json

{ "compilerOptions": { "module": "amd", "target": "es5"  } }

tsconfig.commonjs.json

{ "compilerOptions": { "module": "commonjs", "target": "es5"  } }

Here were the unbundled results: es2015

Error: Unexpected token import

system

<div>Hello</div>

amd

undefined

commonjs

undefined

Here were the bundled results (>jspm bundle app --inject):

es2015

<div>Hello</div>

bundled template.html

System.register("app/template.html", [], function (_export, _context) {
  "use strict";

  var __useDefault;

  return {
    setters: [],
    execute: function () {
      _export("__useDefault", __useDefault = true);

      _export("__useDefault", __useDefault);

      _export("default", "<div>Hello</div>");
    }
  };
});

system

undefined

bundled template.html

System.register("app/template.html", [], function (_export, _context) {
    "use strict";

    return {
        setters: [],
        execute: function () {
            System.register([], function (exports_1, context_1) {
                "use strict";

                var __moduleName = context_1 && context_1.id;
                var __useDefault;
                return {
                    setters: [],
                    execute: function () {
                        exports_1("__useDefault", __useDefault = true);
                        exports_1("default", "<div>Hello</div>");
                    }
                };
            });
        }
    };
});

amd

Error: define is not defined

bundled template.html

"bundle";
System.register("app/template.html", [], function (_export, _context) {
    "use strict";

    return {
        setters: [],
        execute: function () {
            define(["require", "exports"], function (require, exports) {
                "use strict";

                Object.defineProperty(exports, "__esModule", { value: true });
                exports.__useDefault = true;
                exports.default = "<div>Hello</div>";
            });
        }
    };
});

commonjs

Error: exports is not defined

bundled template.html

"use strict";

System.register("app/template.html", [], function (_export, _context) {
  "use strict";

  return {
    setters: [],
    execute: function () {
      Object.defineProperty(exports, "__esModule", { value: true });
      exports.__useDefault = true;
      exports.default = "<div>Hello</div>";
    }
  };
});

On the one hand, the in browser workflow does not work correctly for any module format besides, "system", on the other hand, bundles only work with module format "es2015".

I realize much of this is extraneous to the specific issue but I believe it may well be related as this could well be the result of metadata being set under the wrong circumstances.

Also, some of these results are extremely strange, in particular, bundling under "system" should work. I know that this one has worked in the past and with plugin-text.

aluanhaddad commented 7 years ago

Update If we leave all settings unchanged and install and set transpiler to plugin-babel all 4 configurations work for the in-browser workflow and both the es2015 and the system configurations produce working bundles while the amd and commonjs configurations produce bundles which log undefined for the imported text, but neither throw.

Hopefully this information is helpful.

frankwallis commented 7 years ago

Thank you for taking the time to do this, it is really appreciated and it would be great if we can get to the bottom of some of these interoperability issues. I have looked at the unbundled behaviour and here are my comments:

  1. es2015: Error: Unexpected token import This is expected, es2015 needs to be transpiled to register format to work in the browser. The only scenario when using module: 'es2015' is valid is when you have plugin-babel configured downstream to convert to register format. It would be better if the plugin could output a warning if it is the default transpiler and module is set to es2015 in the browser.

  2. system:

    Hello
    This is the recommended configuration!

  3. amd: undefined

  4. commonjs: undefined

I have responded to the issue on the plugin-text repo. The problem is that plugin-text is outputting an amd module and in typescript to import the default export of an amd/commonjs module you need to use

import template = require('template.html');

Because typescript is not outputting system/es2015 modules it is essentially having to handle the module interop at compile time instead of systemjs handling it at runtime. The problem is compounded by the fact that plugin-text uses esm modules when bundled and amd for unbundled which makes it impossible I think.

Regarding the plugin setting the module format in the metadata, that is code which I would really like to remove, but when I do things stop working.