Как запустить приложение TypeScript, скомпилированное в один файл с модулями AMD?

Я уверен, что здесь я пропустил нечто совершенно тривиальное, но для его жизни я не могу понять это. Только недавно я начал использовать AMD (RequireJS). Мое приложение будет (будет) работать в браузерах.


Настройка

В TypeScript 1.8, возможно до tsc весь проект, состоящий из внешних модулей, в один выходной файл при использовании AMD.

По этой причине я, наконец, решил оставить внутренние модули позади и сделать все мои проекты VS2015 .ts и .tsx внешними модулями, а затем скомпилировать их в один файл со следующими аргументами компилятора:

--module AMD --outFile main.js

Выход

Файл с одним выходом main.js создается, как ожидается, в нем перечислены все модули, которые являются частью проекта:

main.js

define("Project/MainModule", ["require", "exports" ...], function (require, exports ...) {
    "use strict";
    console.log("MainModule defined");
    // ...
});

...    

Использование (?)

Теперь, как мне получить Project/MainModule для запуска из - например - index.html(чтобы он регистрировал "MainModule defined" в консоли)? Я загрузил RequireJS для обработки синтаксиса AMD, а также файл main.js, указанный для немедленной загрузки:

index.html

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

Это правильно загружает main.js, который я обеспечил включением вызова console.log после огромного списка определений в этом файле (внешние модули). Простите меня, если это тривиальный вопрос, я не мог найти ничего о том, как использовать скомпилированное приложение с этим подходом (возможно, я не использовал правильные ключевые слова?).


Изменить: я попробовал модуль с именем:

index.html

<script>
    window.onload = function () {
        require(["Project/MainModule"], function () {
            // this
        });
    }
</script>

... но это нехорошо, RequireJS не может найти модуль.

Ответ 1

Вы должны загрузить встроенный файл с помощью тега script:

<head>
    <script src="bower_components/dojo/dojo.js"></script>
    <script src="built/run.js"></script>
</head>

Затем вы можете загрузить модули, используя require:

<body>
    <script>require(["app"], run => run());</script>
</body>

tsconfig.json:

{
    "compilerOptions": {
        "declaration": false,
        "module": "amd",
        "target": "es5",
        "noImplicitAny": true,
        "sourceMap": false,
        "out": "./built/run.js",
        "moduleResolution": "node"
    },
    "exclude": [
        "bower_components"
    ]
}

См. https://github.com/ca0v/ags-lab/blob/master/index.html для рабочего примера.

В качестве альтернативы вы можете использовать data-main для загрузки конфигурации requirejs. Эта конфигурация может указывать встроенную script как зависимость. Например:

requirejs.config({
    paths: {
        "openlayers": "bower_components/ol3/ol",
        "jquery": "bower_components/jquery/dist/jquery.min"
    },
    deps: ["built/run"],
    callback: () => {
        requirejs(["app"], run => run());
    }
});

И загрузите это с помощью main-данных:

<head>
    <script src="bower_components/requirejs/require.js" data-main="config.js"></script>
</head>

См. https://github.com/ca0v/ol3-lab/blob/master/index.html

Ответ 2

TypeScript компилятор производит только вызовы define. Для запуска загрузки модуля вам потребуется хотя бы один вызов верхнего уровня require.

При использовании RequireJS r.js для связывания по этой причине есть хороший вариант.

Не знаю, как использовать --outFile для достижения этой цели. Я считаю, что вам нужно будет использовать RequireJS API непосредственно в .ts или .js аналогичным образом в вашем index.html. Вызов просто require(["Project/MainModule"]); должен быть достаточным.

Это причина, по которой вы не хотите или не можете использовать решение с r.js, browserify или webpack?

Ответ 3

Это действительно была тривиальная ошибка - для продвинутых пользователей RequireJS.


Определения модулей, созданные при компиляции с синтаксисом AMD и --outFile, называются модулями в соответствии с RequireJS.

Чтобы использовать именованный модуль, он должен быть определен в конфигурации RequireJS путем сопоставления имени модуля с модулем. В этом случае нам нужно определить, что именованный модуль Project/MainModule находится в модуле (файле) main:

index.html

<script>
    require.config({
        paths: {
            "Project/MainModule": "main"
        }
    });
</script>

И затем требуется модуль по его имени, которое теперь можно искать из файла, назначенного ему:

index.html

<script>
    require(["Project/MainModule"], function () {
        console.log("app loaded");
    });
</script>

Примечание: атрибут data-main должен был быть опущен при включении Require.js, иначе модуль будет загружен дважды (или, по крайней мере, приведенный выше пример дважды записывался в журнал).

Примечание 2: это только часть полного решения. Сопоставления module -> file должны быть указаны для всех модулей, выпущенных компилятором TypeScript, что вообще невозможно. Однако этот связанный вопрос имеет применимый .