0

I've read tones of articles, but none of them works. The thing is that - I have a .net core WebApplication with some typescript code (instead of javascript) and:

  • I want to be able to debug it in Visual Studio

  • I want to be able to use other modules

  • I want to be able to call JS functions from withing my html files, for example:

    <button onclick="myTypeScriptFunction()">OK</button>

This is my project tree (some folders and files were deleted for clarification):

- wwwroot
  + css
  + imgs
  - js <-- these files are created by compiling TypeScript
    app.js
    ajaxmanager.js
    etc...

+ node_modules
- Scripts <-- this is folder with my typescript files
  ajaxmanager.ts
  app.ts

package.json
tsconfig.json

No, my package.json looks like that:

{
  "version": "1.0.0",
  "name": "asp.net",
  "private": true,
  "devDependencies": {
    "@types/jquery": "3.5.0",
    "@types/bootstrap": "4.5.0",
    "@types/jquery-validation-unobtrusive": "3.2.32",
    "@syncfusion/ej2": "*",
    "autonumeric": "4.6.0"
  }
}

My tsconfig.json:

{
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "ES5",
    "outDir": "wwwroot/js",
    "esModuleInterop": true,
    "module": "CommonJS"
  },
  "compileOnSave": true,
  "include": [
    "scripts/**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}

And that is all I have. All I get while loading my website are bunch of errors. The legendaryL "exports is not defined", but I was able to resolve this by just declaring exports on main page:

<script>var exports = {}</script>

But then I was getting other errors like require is not defined. I have read that this comes from node.js. But I am not using node.js, so why it compiles that way?

On some configurations (I mean "tests" with my tsconfig.json) I was able to run my page, but it wasn't working. For example. I have a button:

<button onclick="btnClick(this)">Click me</button>

<script>
function btnClick(btn)
{
  exports.MyCustomPageClass.foo(btn);
}
</script>

MyCustomPageClass is just my class written in typescript. I noticed that TypeScript compiles to JavaScript in such way that it creates objects in exports variable. So this one should work. Instead MyCustomPageClass was undefined. Sometimes (in some configurations) exports had only AutoNumeric object (from AutoNumeric module), sometimes it had some of my classes. Not all of them.

So, right now, I am very close to shooting myself in head. It's been a week since I try to configure everything properly. So, can anyone tell me step after step, what should I do to make it work?

I tried also webpack and gulp. But the errors were rather the same, or none was working.

2
  • You can't use Typescript in a browser. A browser only understands Javascript. You have to compile your .ts to .js before you provide to the browser. You can debug with the help of map files so you know which line of .js matches which line in .ts file Commented Aug 3, 2020 at 11:00
  • I do it. My ts files are compiled into js and js files are included in html. But I am getting errors that I wrote. Commented Aug 3, 2020 at 11:17

2 Answers 2

3

OK, for those struggling with the same topic... I figured it out. Now you can have debuggable TypeScript in your .NetCore razor project.

So, these are the steps you have to follow:

  1. Make sure you have node.js installed in Visual Studio. Just run Visual Studio Installer, click Modify button near your VS version, find module Node.js and make sure it's checked.
  2. Do the steps required to have typescript in your project - follow this small article: https://learn.microsoft.com/pl-pl/visualstudio/javascript/tutorial-aspnet-with-typescript?view=vs-2019
  3. Make sure that you have in your package.json things like (inside devDependencies):
"@types/jquery": "3.5.0",
"@types/bootstrap": "4.5.0",
"@types/jquery-validation-unobtrusive": "3.2.32"

and other that you use. These above just gives you TypeScript types for jQuery, bootstrap and jqueryValidation. JQuery, Bootstrap and JQueryValidation are defaultly used by .NetCore Razor Pages/MVC, so I suppose you use it as well.

  1. Make sure that your tsconfig.json looks like that:
{
  "compilerOptions": {
    "noImplicitAny": false,
    "noEmitOnError": true,
    "removeComments": false,
    "sourceMap": true,
    "target": "ES6",
    "outDir": "wwwroot/js",
    "esModuleInterop": true,
    "module": "AMD",
    "moduleResolution": "Node"
  },
  "compileOnSave": true,
  "include": [
    "scripts/**/*"
  ],
  "exclude": [
    "node_modules"
  ]
}

The most important here, I think, are:

  • target set to ES6 (but you can try with ES5 also)
  • esModuleInterop set to true
  • module set to AMD (this means that modules will be loaded asynchronously - this is default for browsers, I think
  • moduleResolution set to Node
  1. In your .ts files use exports and imports. For example: person.ts:
export class Person
{
   //your code here
}

export function foo()
{
  //your code here
}

In other file, for example:

import { Person } from "./person";

export class ClassThatUsesPerson
{
    _person: Person;
   //your code goes here
}

Just make sure that you import your file WITHOUT "ts" extension, so: "./person" instead of "./person.ts". And "./" should be at the start

  1. You can import other libraries that you use and have installed using npm - similar way. Let's say I use "autonumeric" library that I have installed by npm, so in my file I will import it like that:
import AutoNumeric from 'autonumeric'
  1. Download library: requireJS (you will find it in google)
  2. Make some changes to your _Layout.cshtml:
  • get rid off jQuery and bootstrap from header. Provided that you have your requireJS copied into: "~/libs/requirejs.js", you should include it like that:
    <script src="~/lib/requirejs.js"></script>
    <script src="~/js/entrypoint.js"></script>

Now, I assume that you will keep your js files in "~/js" folder. So now, you should create there entrypoint.js which should look like that:

requirejs.config({
    baseUrl: "/js",
    shim: {
        bootstrap: {
            "deps": ["jquery"]
        }
    },
    paths: {
        jquery: "https://ajax.googleapis.com/ajax/libs/jquery/3.5.0/jquery.min",
        bootstrap: "https://maxcdn.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.bundle.min",
        "jquery-validation": "https://cdn.jsdelivr.net/npm/[email protected]/dist/jquery.validate.min",
        "jquery.validate.unobtrusive": "https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min"
    }
});

require(["jquery", "bootstrap", "app"], function (jq, bs, app) {
    app.App.init();
});

Now, some things: At the start you have to configure your requirejs lib (go to requirejs homepage and read aboutr configuration). In short: baseUrl is the default place where requirejs will search for your js files shim - this is needed for bootstrap to work properly paths - this is where you can define your modules paths. Just add here libraries that you don't have in your JS folder and would get from CDN or such. Those three here (jQuery, bootstrap and jQuery validations) are needed if you use jquery, bootstrap and jquery validation :) Important - make sure that you include here bootstrap.bundle.min, instead of bootstrap.min. The bundle version has some references inside (for example to popper.js) which makes things a lot of easier.

WARNING! Name of modules: "jquery-validation" and "jquery.validate.unobtrusive" are important. These modules have to be named exactly like that (especially jquery-validation). In other case validation will not work.

Now, after configuration is done, you can see in my file:

require(["jquery", "bootstrap", "app"], function (jq, bs, app) {
    app.App.init();
});

This just tells: Now load, jquery module, bootstrap module and app module. Notice that app module is my custom class. init() is static function inside App class. I do here things that normally would go to document.ready or body.onload.

In the last step - make sure that you DO NOT HAVE any <script src="..."> in your code. Now, using requirejs you load every script using require function.

So for example, somewhere in your page instead of having:

<script src="~/js/person.js"></script>

you should have:

require(["person"]);

or even, if person is a class and you want to create object of it:

var personObj;
require(["person"], function(personFile) {
  personObj = new personFile.Person();
});

That's it. Really simple, isn't it? ;) Hurray me!

Sign up to request clarification or add additional context in comments.

Comments

0

Please check where you add the .js script references, perhaps the issue is that the related JS file doesn't add success or add after calling them.

From the Microsoft document, we can see that after create the TypeScript file, we need to rebuild the solution and generate the .js file. Then, add the script reference before the call to @RenderSection("Scripts", required: false) in the _Layout.cshtml, after that, we could call the related function in the TypeScript file and debug it.

Code like this:

<script src="~/js/app.js"></script>
<script src="~/js/ajaxmanager.js"></script>
@RenderSection("Scripts", required: false)

More detail information about using ASP.NET Core app with TypeScript, please check this article:

Create an ASP.NET Core app with TypeScript in Visual Studio

4 Comments

This is not the issue in my case. Every js files are created. I noticed that the real problem is rather 'require' instruction that is created in compiled js files.
OK, I understand, can you post the related code (in the compiled js file), so that, I could try to reproduce the problem on my side and help you solve this issue.
OK I figured it out that I needed requireJS for this to work. But still have problems with jquery and bootstrap. For example "Undefined $" or "popper.js" which is required by bootstrap
Congratulation. About the "$ Undefined " error, please check whether the JQuery reference load success, and make sure the JQuery reference load before other JavaScript reference. Besides, whether you are using a layout page or not? Please check whether it also adds the JQuery reference or not, perhaps you are meeting the JQuery Conflict issue, you could refer to this thread.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.