3
votes

I'm using typescript and requirejs. I want to import my library code as modules, to avoid making everything an ambient global. My problem is that any use of import or export in a typescript file turns the entire file into a module. In the case of my application code, this means it can't be invoked directly.

Here's a sample app.

index.html

<!DOCTYPE html>
<html>
    <head>
        <title>My Test App</title>
        <script src="require.js"></script>
        <script src="app1.js"></script>
        <script src="app2.js"></script>
    </head>
</html>

tsconfig.json

{
    "compilerOptions": {
        "module": "amd",
        "target": "es5",
        "noImplicitAny": false,
        "sourceMap": false
    }
}

greeter.ts

export function greet(name: string) {
    alert(`Hello ${name}`);
}

app1.ts

import { greet } from './greeter';
greet('alice');

app2.ts

import { greet } from './greeter';
greet('bob');

tsc runs with no problem, but here's one of the files I get as output.

tsc output: app1.js

define(["require", "exports", './greeter'], function (require, exports, greeter_1) {
    "use strict";
    greeter_1.greet('alice');
});

That doesn't work. From require.js

Be sure to load all scripts that call define() via the RequireJS API. Do not manually code script tags in HTML to load scripts that have define() calls in them.

So how can I convince the typescript compiler to produce output without a define() call in it. In app1.ts, I don't intend to define a module, just consume other modules. require() seems more appropriate for that. Is there a way to make import compile to require()?

2

2 Answers

3
votes

If you have a single module kicking off everything that needs to load for your page, you can use data-main. If you need to kick off the loading with more than one module, then use require to load the modules:

<script src="require.js"></script>
<script>
  require(["app1", "app2"]);
</script>

You may be used to always passing a single string argument to require, but this is AMD. The native AMD require takes an array of dependencies as the first argument, and an optional callback as the 2nd.

If you are using require.config you can use the deps option for the same purpose:

<script src="require.js"></script>
<script>
  require.config({
    // You could have more config here... in addition to:
    deps: ["app1", "app2"]
  });
</script>

There's currently no way to get tsc to output require instead of define. I would not hold my breath waiting for such a feature to be added because there are readily available ways to get the same end results that such a feature would allow.

0
votes

Fix

From the docs you already found:

Be sure to load all scripts that call define() via the RequireJS API.

Also from the docs start page : http://requirejs.org/docs/start.html

and only reference require.js with a requirejs call like so to load your script:

<script data-main="scripts/main" src="scripts/require.js"></script>

^ this is the script tag that should load your application entry point.

More

So how can I convince the typescript compiler to produce output without a define() call in it.

Yes. But if you want to use requirejs, then this is the wrong question to be asking. The fix is as I mentioned, i.e. use the correct script tag.