10
votes

I'm writing a web app using TypeScript, Backbone, and Mustache. I want to use Requirejs for dependency loading.

I'm also using the Web Essentials visual studio plugin for TypeScript with the AMD compilation option turned on. For those that are not familiar with this, it will wrap your type script file in an AMD module if you import external modules. For example:

In type script I import the following modules in type definition files.

export import Backbone = module("Backbone"); 
import mainTemplate = module("MainTemplate");

The output is something like:

define(["require", "exports", "Backbone", "MainTemplate"], function(require, exports, __Backbone__, __mainTemplate__) {
//...code goes here ...
});

For the template, I've declared the following in a type definition file:

declare module "MainTemplate" { }

In order to support requirejs plugins, you need to declare your module as:

declare module "text!MainTemplate.html" { }

I'd like to keep the module name free of plugins and file extensions. This would leave me with some flexibility in the future.

I have the following mapping in require.

require.config({
    map: {
        "MyModule": {
            "MainTemplate": "text!MainTemplate.html"
        }
    }
}

This successfully invokes the text plugin however, the plugin loads the wrong url. Sifting through the source code for the text plugin, I found that the following code is the culprit.

load: function (name, req, onLoad, config) {
  ...
  url = req.toUrl(nonStripName),
  //returns "scripts/**text!**MainTemplate.html**.html**"
  ...
}

If I name the module, 'MainTemplate.html' it works fine but I'd like to keep the extension out of the module name.

I've modified the text plugin with a simple regex replacement to strip out the plugin reference and the duplicate extension.

Is there a better way to handle this?

5

5 Answers

11
votes

Ran into similar issue. Solved finally. See TypeScript: compiling removes unreferenced imports

/// <amd-dependency path="text!templates/application.htm" />

var applicationTemplate = require('text!templates/application.htm');
9
votes

For Typescript 1.0 this works for me. First I created a .d.ts file which stores all module declarations for each text template.

//workaround for typescript's lack of support for requirejs text template notation
//remember that a reference to the import variable has to be found in the class, otherwise typescript ignores the import
declare module "text!views/details/details.html" {
    var text: string;
    export = text;
} 
declare module "text!views/layout/layout.html" {
    var text: string;
    export = text;
} 
declare module "text!views/home/home.html" {
    var text: string;
    export = text;
} 

then to refer to the text template I add these lines on top of the class/module.

/// <reference path="../texttemplate.d.ts"/>
import detailsTemplate = require('text!views/details/details.html');

The reference line is not actually needed, since the .d.ts file is picked up globally. But I added it as a reminder of the workaround. It also makes it easy to ctrl+click to go the d.ts. file.

5
votes

There is a slightly nicer way to do this (I'm using typescript 2.0) Referenced here: https://www.typescriptlang.org/docs/handbook/triple-slash-directives.html

This code expects that your requirejs configuration and plugins are set up correctly:

/// <amd-dependency path="text!./about.html" name="template"/>
declare let template: string;

This helped me a lot to migrate lagacy code to typescript.

2
votes

Since TypeScript 0.9.0 I think you need to do the following:

/// <amd-dependency path="text!templates/application.htm" />
declare var require:(moduleId:string) => any;
var applicationTemplate:string = require("text!templates/application.htm");

Check out more at http://www.codebelt.com/typescript/typescript-amd-with-requirejs-tutorial/

0
votes

We are using Backbone and require.js for our TypeScript applications.
We don't use the

import backbone = module("Backbone")

syntax, but rather use a

/// <reference path="../../modules/Backbone.d.ts" />

reference, and then a BootStrapper.
This way, the 'text!htmlfile.html' syntax works perfectly with require.js.

I've put together a blog on using require.js with TypeScript and AMD: http://blorkfish.wordpress.com/2012/10/23/typescript-organizing-your-code-with-amd-modules-and-require-js/