Can't access exported functions in bundled .js file using esbuild - javascript

I want to create a library using TypeScript. It should be available for Node and Browser environments.
I started with the package.json file and installed esbuild as a dependency and typescript as a dev dependency. The result is
{
"name": "my-lib",
"version": "1.0.0",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"scripts": {
"build": "tsc && esbuild ./dist/lib/index.js --bundle --minify --sourcemap --outfile=./bundle/index.js"
},
"dependencies": {
"esbuild": "0.14.36"
},
"devDependencies": {
"typescript": "4.6.3"
}
}
The tsconfig.json file contains
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"esModuleInterop": true,
"lib": [ "dom", "esnext" ],
"module": "commonjs",
"outDir": "dist",
"resolveJsonModule": true,
"strict": true,
"target": "es2019",
},
"include": [
"./**/*.ts"
],
"exclude": [
"./dist"
]
}
Inside the root directory I have a lib directory holding an index.ts file which exports all the "public" functions, e.g.
const sum = function (a: number, b: number): number { return a + b; };
export { sum };
Besides that I have a test directory right next to the lib directory, holding some .ts files. I want to test the build script and added the following index.html to the root directory
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='./bundle/index.js'></script>
</head>
<body>
<div>
Loading bundle...
</div>
</body>
</html>
<script type="text/javascript">
window.onload = () => {
console.log('ready');
const result = sum(1, 2);
console.log({ result });
const anotherResult = window.sum(1, 2);
console.log({ anotherResult });
};
</script>
Unfortunately I get an Uncaught ReferenceError because it is not able to find the function sum. The folder structure before running npm install && npm run build is
Does someone know what's wrong or missing here?

If you want include your bundled javascript into html file via script tag (as in your example), you should add sum variable to page global variables scope like that:
const sum = function (a: number, b: number): number { return a + b; };
window.sum = sum;
// or `globalThis.sum = sum;`
Defining variable in global page scope makes it sure that no minification or renaming processes in bundler will break your app.

It would be better for you to check the concept of Commonjs and ECMAScript Module(ESM) before working. The compilerOptions.module in tsconfig.json is Commonjs, which is the bundling method used by Node.js. This does not work with browser. This is because the browser does not have the require method which can recognize the exports object and the module object, which is available globally in Node.js.
Therefore, when creating modules that support browsers, usually bundle them in UMD format using Webpack. If you don't support older browsers, you can think of bundling in the ESM way, even without a Webpack.
First, modify tsconfig.json as follows:
{
"compilerOptions": {
"baseUrl": ".",
"declaration": true,
"esModuleInterop": true,
"lib": [ "dom", "esnext" ],
"module": "esnext", // update
"outDir": "dist",
// "resolveJsonModule": true,
"strict": true,
"target": "es2019",
},
"include": [
"./**/*.ts"
],
"exclude": [
"./dist"
]
}
Next, modify the following HTML as follows:
<!DOCTYPE html>
<html>
<head>
<script type="module">
import {sum} from './dist/index.js';
window.onload = () => {
console.log('ready');
const result = sum(1, 2);
console.log({ result });
const anotherResult = sum(1, 2);
console.log({ anotherResult });
};
</script>
</head>
<body>
<div>
Loading bundle...
</div>
</body>
</html>
You can create library that work in your browser after npm install && npm run build.
If your library can be imported from another bundler (like a webpack), you want it to work in a browser, and you want to implement it using tsc only, see the following link.

Your code is fine, the problem is that you are using bad export. Exports a function that is never used and that is why the error. Then I show you how to solve this.
You must first bear in mind that nothing is exported in the index.ts. Rather the index.ts receives functions from other JS modules. Then create a Sum.TS file that will be a module where you will write the following code:
sum.ts
const sum = function (a: number, b: number): number { return a + b; };
export { sum };
In Index.ts imports the sum function of the module sum.ts the file must remain like this:
index.ts
import { sum } from "./sum";
sum
In this way you already have the sum function available to use in the index.html.
When you export functions these are not available in the compiled code. Only imports are available in the compiled code.
If you want to use the index.ts to store public functions the code should be like this:
const sum = function (a: number, b: number): number { return a + b; };
sum
update
Just change your index.ts to this:
const sum = function (a: number, b: number): number { return a + b; };
sum
and your index.html to this:
<!DOCTYPE html>
<html>
<head>
<script type='text/javascript' src='./bundle/index.js'></script>
</head>
<body>
<div>
Loading bundle...
</div>
</body>
</html>
<script type="text/javascript">
window.onload = () => {
console.log('ready');
const result = sum(1, 2);
console.log({ result });
const anotherResult = sum(1, 2);
console.log({ anotherResult });
};
</script>
Don't export functions in index.ts as you won't be able to do them in the browser.

Related

Typescript not bundling modules

I have a node application that compiles typescript files to a dist folder and then serves these files as lambda resolvers via aws cdk. Here is an example of my setup:
The code
register.ts
import ValidateUserFields from '../utils/forms';
exports.main = async function (event: any, context: any) {
return {
statusCode: 200,
};
}
register-lambda-config.ts
import { Construct } from 'constructs';
import * as apigateway from 'aws-cdk-lib/aws-apigateway';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as s3 from 'aws-cdk-lib/aws-s3';
export class FrontendService extends Construct {
constructor(scope: Construct, id: string) {
super(scope, id);
const api = new apigateway.RestApi(this, 'frontend-api', {
restApiName: 'Frontend Service',
description: 'This service serves the frontend.',
});
const functionName = 'register';
const handler = new lambda.Function(this, functionName, {
functionName,
runtime: lambda.Runtime.NODEJS_14_X,
code: lambda.Code.fromAsset('dist/src/lambda'),
handler: 'register.main',
});
const registerIntegration = new apigateway.LambdaIntegration(handler, {
requestTemplates: { 'application/json': '{ "statusCode": "200" }' },
});
const registerResource = api.root.addResource('register');
registerResource.addMethod('POST', registerIntegration);
}
}
tsconfig.json
{
"compilerOptions": {
"target": "ES2018",
"module": "commonjs",
"moduleResolution": "node",
"lib": ["es2018"],
"declaration": true,
"strict": true,
"noImplicitAny": false,
"strictNullChecks": true,
"noImplicitThis": true,
"alwaysStrict": true,
"esModuleInterop": true,
"noUnusedLocals": false,
"noUnusedParameters": false,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": false,
"inlineSourceMap": true,
"inlineSources": true,
"experimentalDecorators": true,
"strictPropertyInitialization": false,
"outDir": "dist",
"typeRoots": ["./node_modules/#types"]
},
"exclude": ["node_modules", "cdk.out", "./dist/**/*"]
}
And finally here is the script part of my package.json file:
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"cdk": "cdk",
"bootstrap": "cdk bootstrap",
"deploy": "cdk deploy && rimraf cdk.out",
"destroy": "cdk destroy",
"run-same-local-fe-api": "sam local start-api -p 4000 -t ./template.yaml",
"dev": "npm run build && npm run synth && concurrently --kill-others \"npm run watch\" \"npm run run-same-local-fe-api\"",
"synth": "cdk synth --no-staging > template.yaml"
},
The problem
When I run npm run dev it compiles my typescript files to the dist folder in the same structure as what I have in my src folder (where all my typescript files live). I however run into the following error if I have any imports in my register.ts file:
{"errorType":"Runtime.ImportModuleError","errorMessage":"Error: Cannot
find module '../utils/forms'\nRequire stack:\n-
/var/task/register.js\n- /var/runtime/UserFunction.js\n-
/var/runtime/index.js","stack":["Runtime.ImportModuleError: Error:
Cannot find module '../utils/forms'","Require stack:","-
/var/task/register.js","- /var/runtime/UserFunction.js","-
/var/runtime/index.js"," at _loadUserApp
(/var/runtime/UserFunction.js:202:13)"," at
Object.module.exports.load (/var/runtime/UserFunction.js:242:17)","
at Object. (/var/runtime/index.js:43:30)"," at
Module._compile (internal/modules/cjs/loader.js:1085:14)"," at
Object.Module._extensions..js
(internal/modules/cjs/loader.js:1114:10)"," at Module.load
(internal/modules/cjs/loader.js:950:32)"," at Function.Module._load
(internal/modules/cjs/loader.js:790:12)"," at
Function.executeUserEntryPoint [as runMain]
(internal/modules/run_main.js:75:12)"," at
internal/main/run_main_module.js:17:47"]}
This happens for imports from relative local files (like '../utils/forms' as shown in the code above) but also for imports from node_modules. When I look into the compiled register.js file in the dist folder I see that it has made an attempt to parse the import:
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const forms_1 = __importDefault(require("../utils/forms"));
const bucketName = process.env.BUCKET;
exports.main = async function (event, context) { ...
however it shows the error message above. I have tried using require instead of import but it was the same result...
Any help would be greatly appreciate! Thanks
Stated that this is really hard to answer without a minimal reproducible example; I would at least suggest to avoid any require and exports, and to use only import / export statements and following in tsconfig.json.
{
"compilerOptions": {
"module": "esnext"
}
}
Well.. I do understand that you want your main function to look something like this:
// final result written in javascript
exports.main = async function (event, context) {
return {
statusCode: 200,
};
}
But... using module.exports in Typescript is not the way to achieve that. Instead, Typescript using export directive (no s at the end of it) to define which parts of your code should be export. It's then up to your tsconfig.json file to determine which syntax will be used in order to represent this export (this is actually a part of Typescript engine)
So... a script written like this in Typescript
export async function main(event: any, context: any) {
return {
statusCode: 200,
};
}
Will be parse in Typescript as follow (I've used module: commonjs to achieve below result)
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.main = void 0;
async function main(event, context) {
return {
statusCode: 200,
};
}
exports.main = main;
//# sourceMappingURL=test.js.map
Please note how the resulted js file correctly use modile.exports and main as you intended
In short: when using Typescript, please use the language directives and let the engine to do the rest for you. This way - a single source of code can be deployed for different environment without requireing changing your app logic. Neat!

Build for both browser and nodejs

I am trying to make a library that works both in the browser as well as in node.
I have three json config files where the latter two extend tsconfig.json
tsconfig.json (just contains files for the build)
tsconfig.browser.json
tsconfig.node.json
tsconfig.browser.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"target": "es6",
"module": "system",
"outFile": "../dist/browser/libjs.js",
"removeComments": true,
"declaration": true
}
}
tsconfig.node.json
{
"extends": "./tsconfig.json",
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"outDir": "../dist/node",
"removeComments": true,
"declaration": true,
"declarationDir": "../dist/node/typings"
},
"files": [
"./index"
]
}
I have this index.ts file (only included on the node build):
export { collect } from './components/collections'
export { query } from './components/query'
Then I have this in the collections.ts file:
export namespace libjs {
export function collect<T>(data: T[]) {
// Do some stuff
}
export class collection(){}
}
And this query.ts file:
export namespace libjs {
export class query<T> {
private _results: collection<T>
}
}
The issue I am having, is when I try to build to node, the index file cannot find the collect function, and when I build to the browser the query class cannot find the collection class. What is the best way to code this so I can build to both node and the browser? If I remove the export on the namespace I can build to the browser fine, but I cannot build to node.
The way I would like to use these are as follows:
Nodejs
const libjs = require('libjs')
let c = libjs.collect([1, 123, 123, 1231, 32, 4])
Browser
<script src="/js/libjs.js"></script>
<script>
let c = libjs.collect([1, 123, 123, 1231, 32, 4])
</script>
When you compile files that have export ... at the top level, each file is treated as a module with its own scope, and namespace libjs in each file is distinct and separate from libjs in every other file.
If you want to generate a single script that can be used in a browser without module loader (defining libjs as global), you have to remove all toplevel exports, and don't set module at all in tsconfig:
components/collections.ts
namespace libjs {
export function collect<T>(data: T[]) {
// Do some stuff
}
export class collection<T>{}
}
components/query.ts
namespace libjs {
export class query<T> {
private _results: collection<T>
}
}
Now, you can use the same generated script in node too, if you add code that detects node environment at runtime and assigns libjs to module.exports:
index.ts
namespace libjs {
declare var module: any;
if (typeof module !== "undefined" && module.exports) {
module.exports = libjs;
}
}
single tsconfig.json for browser and node (note that I changed output to dist from ../dist)
{
"compilerOptions": {
"outFile": "./dist/libjs.js",
"removeComments": true,
"declaration": true
},
"files": [
"components/collections.ts",
"components/query.ts",
"index.ts"
]
}
You can use generated script right away in node in javascript:
test-js.js
const lib = require('./dist/libjs')
console.log(typeof lib.collect);
let c = lib.collect([1, 123, 123, 1231, 32, 4])
Unfortunately, you can't use it in node in typescript with generated libjs.d.ts because it declares libjs as global. For node, you need separate libjs.d.ts that contains one additional export = libjs statement that you have to add manually or as part of build process:
complete dist/libjs.d.ts for node
declare namespace libjs {
function collect<T>(data: T[]): void;
class collection<T> {
}
}
declare namespace libjs {
class query<T> {
private _results;
}
}
declare namespace libjs {
}
// this line needs to be added manually after compilation
export = libjs;
test-ts.ts
import libjs = require('./dist/libjs');
console.log(typeof libjs.collect);
let c = libjs.collect([1, 123, 123, 1231, 32, 4])
tsconfig.test.json
{
"compilerOptions": {
"module": "commonjs",
"moduleResolution": "node",
"removeComments": true
},
"files": [
"./test-ts.ts",
"./dist/libjs.d.ts"
]
}
You can choose to go a completely different route and build a library composed of modules, but for that you have to use module loader in the browser (or build with webpack), and you probably need to read this answer explaining why namespace libjs is totally unnecessary with modules.

Auto generate index.d.ts, type definitions, from a typescript module

If I have a TypeScript module saved as my-function.ts as follows :
export function myFunction (param: number): number { return param }
This will be compiled to JavaScript in whichever way and loose its type definitions. I am then able to create a index.d.ts file which declare this module's definitions, but this seems a bit tedious to redefine/redeclare the definitions.
Are there ways to generate the type definitions automatically from the my-function.ts file to a index.d.ts file?
If you compile with the --declaration flag, TypeScript will automatically generate .d.ts files for you.
This mode will require that you certain types are visible so that they can be described in your .d.ts files.
Here's how I managed to solve it:
Creating the infra
Create an new Node package with typescript for the infra.
Inside the new package, make sure to configure a tsconfig.json with declaration:true Doing so will cause typescript to generate definition files which can be consumed by the users of this infra.
My tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"module": "commonjs",
"declaration": true,
"outDir": "./tsOutputs"
},
"include": [
"lib/**/*.ts",
"index.ts"
],
"exclude": [
"test/**/*.ts"
]
}
Create a an "index.ts" file which will export the public API of the infra.
Note: In order to be able to cast & create instances of objects, you need to have two different exports per each entity. Once as type and another as const.
Here's my index.ts:
import {HttpClient as HC} from "./lib/http/http-client";
import {HttpRequest as HReq, HttpResponse as HRes} from "./lib/http/contracts";
export namespace MyJsInfra {
export type HttpClient = HC;
export namespace Entities {
export type HttpRequest = HReq;
export const HttpRequest = HReq;
export type HttpResponse = HRes;
export const HttpResponse = HRes;
}
}
You can read more info on the reasoning behind this dual declaration in here:
https://github.com/Microsoft/TypeScript/issues/10058#issuecomment-236458961
After all of the following, when we'll run build we should have the corresponding "*.d.ts" files per each type. Now we have to handle the package.json of the infra, in order to pack all the items.
Inside the package.json make sure to set the types, main to point to the generated index.d.ts & index.js files.
In addition, you have to make sure that the "*.d.ts" files are being packaged as part of infra. In my case, I've specified the following pattern in the files property: "tsOutputs/**/*.d.ts"
Here's my package.json:
{
"name": "my-js-infra",
"version": "1.0.0",
"description": "Infrastructure code.",
"scripts": {
"build":"./node_modules/.bin/tsc -p .",
"prepublish":"npm run build",
},
"homepage": "https://github.com/Nadav/My.JS.Infra#readme",
"devDependencies": {
...
"typescript": "^2.4.2",
...
},
"dependencies": {
...
"needle": "^1.4.2",
...
},
"files": [
"tsOutputs/**/*.js",
"tsOutputs/**/*.d.ts",
"tsOutputs/index.d.ts"
],
"types":"tsOutputs/index.d.ts",
"main":"tsOutputs/index.js"
}
All done. Now you can publish your common code.
Consuming the code
Install the infra. In our case the user have to use: npm install my-js-infra --save
Modify the tsconfig.json of the consuming application to load the modules using the Node module resolution. You do so by setting moduleResolution:true inside the file.
Here's my tsconfig.json:
{
"compilerOptions": {
"target": "es5",
"lib": ["es5", "es6"],
"module": "umd",
"sourceMap": true,
"watch": false,
"outDir": "./tsOutputs",
"moduleResolution":"node" /* This must be specified in order for typescript to find the my-js-infra. Another option is to use "paths" and "baseUrl". Something like:
...
"baseUrl": ".", // This must be specified if "paths" is used.
"paths":{
"my-js-infra":["node_modules/my-js-infra/tsOutputs/index.d.ts"]
}
...
*/
}
}
You can read more on module resolution in Typescript in here:
https://www.typescriptlang.org/docs/handbook/module-resolution.html
Start using the code. For example:
import {MyJsInfra } from "my-js-infra";
public doMagic(cmd, callback) {
try {
var request: MyJsInfra.Entities.HttpRequest = {
verb: "GET",
url: "http://www.google.com",
};
var client = new MyJsInfra.HttpClient();
client.doRequest(request, (err, data) => {
if (err)
return callback(err, null)
return callback(null, data);
})
} catch (err) {
callback(err);
}
}

How to properly import and use the MSAL (Microsoft Authentication Library for js) into a typescript react single page application?

Problem
I can't seem to get the MSAL library to import properly into my typescript code. I'm using the MSAL for JS library (which is supposed to have typings) in a simple typescript/react project scaffolded using the create-react-app with react-typescript scripts. I'm new to typescript and not sure if I'm missing something obvious or if there is a problem with the MSAL package when using it with typescript projects.
Details:
I added the MSAL package from NPM using npm install --save msal.
I attempted to import the MSAL into my .ts using different forms of import {Msal} from 'msal';
This results in a typescript error Could not find a declaration file for module 'msal'. '<path>/node_modules/msal/out/msal.js' implicitly has an 'any' type.
Thinking that was odd, I looked at the the node_module/msal/out folder and saw a 'msal.d.ts' file, which is what I would expect.
When I look at the contents of the msal.d.ts file, I don't see any exports, which I would normally expect to see.
I tried install the declaration from #types using npm install --save-dev #types/msal, but it doesn't exist.
I also tried importing it into my file using let Msal = require('Msal');, but get an error that the Msal.UserAgentApplication isn't a constructor.
I didn't have much luck trying to use the /// reference directive and adding a script tag to the main index.html. This also doesn't feel like the right way to solve the problem.
ExampleMsal.ts
import { observable, action, computed } from 'mobx';
import * as Msal from 'msal'; // <-- This line gives the error
class ExampleMsal{
#observable
private _isLoggedIn: boolean;
constructor() {
this._isLoggedIn = false;
}
#computed
get isLoggedIn(): boolean {
return this._isLoggedIn;
}
#action
signIn() {
let userAgentApplication = new Msal.UserAgentApplication('<client-id>', null,
function (errorDes: string, token: string, error: string, tokenType: string) {
// this callback is called after loginRedirect OR acquireTokenRedirect
// (not used for loginPopup/aquireTokenPopup)
}
);
userAgentApplication.loginPopup(['user.read']).then(function(token: string) {
let user = userAgentApplication.getUser();
if (user) {
// signin successful
alert('success');
} else {
// signin failure
alert('fail');
}
}, function (error: string) {
// handle error
alert('Error' + error);
});
this._isLoggedIn = true;
}
#action
signOut() {
this._isLoggedIn = false;
}
}
export default ExampleMsal;
tsconfig.json
{
"compilerOptions": {
"outDir": "build/dist",
"module": "commonjs",
"target": "es5",
"lib": ["es6", "dom"],
"sourceMap": true,
"allowJs": true,
"jsx": "react",
"moduleResolution": "node",
"rootDir": "src",
"forceConsistentCasingInFileNames": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"experimentalDecorators": true
},
"exclude": [
"node_modules",
"build",
"scripts",
"acceptance-tests",
"webpack",
"jest",
"src/setupTests.ts"
],
"types": [
"typePatches"
]
}
It looks like the latest version of MSAL.js does have a CommonJS export. You can now just do the following in TypeScript (tested with version 2.3.3 of TypeScript and 0.1.3 of MSAL.js):
import * as Msal from 'msal';
Now in your .ts (or in my case .tsx file) you can, for instance, setup a click event handler and create a UserAgentApplication object:
// In you class somewhere
private userAgentApplication: any = undefined;
// The login button click handler
handleLoginClick = (event: any): void => {
if (!this.userAgentApplication) {
this.userAgentApplication = new Msal.UserAgentApplication(
'clientID string', 'authority string or empty', this.authCallback, { cacheLocation: 'localStorage'});
}
// Other login stuff...
}
// In React render()
public render() {
return (
<Button
bsStyle="warning"
type="button"
onClick={(e) => this.handleLoginClick(e)}
>
Log in
</Button>
);
}
As you have correctly mentioned - in the msal.d.ts there are no exports - its not a module, and therefore you should not try importing.
Instead you can use it like this:
/// <reference path="./node_modules/msal/out/msal.d.ts" />
const userAgentApplication = new Msal.UserAgentApplication("your_client_id", null, (errorDes, token, error, tokenType) =>
{
});
Note that even in readme they specify only one way of using their library - by including script tag, not by importing module. And further looking into their source code shows they are not using modules as well.
I had the same issue and couldn't wait for the author to fix it, so forked and modified the original code. Just as a temporary fix you can use my version msalx instead of msal.
npm install msalx
You can find the source code and an example usage in react at: https://github.com/malekpour/microsoft-authentication-library-for-js#example
If you install the exports-loader (npm install exports-loader --save-dev) you can avoid the script tag and add the following to your directives:
var Msal = require("exports-loader?Msal!../../../node_modules/msal/out/msal.js");

TypeScript export and import Module name has not been loaded yet for context: _. Use require([])

When I try to run the application in the browser I get in the debug console window the following message:
Module name "Person" has not been loaded yet for context: _. Use require([])
Of course if merge the content of the .ts files all is working perfectly.
I create the Person.ts file:
export interface IPerson {
firstName: string;
lastName: string;
}
export class Person implements IPerson {
private _middleName: string;
public set middleName(value: string) {
if (value.length <= 0)
throw "Must supply person name";
this._middleName = value;
}
public get middleName(): string {
return this._middleName;
}
constructor(public firstName: string, public lastName: string) { };
Validate() {
alert('test');
}
}
and the app.ts file:
import {Person} from "./Person"
class Employee extends Person {
Validate() {
alert('new test inside Employee');
}
}
let p1 = new Person("Shahar", "Eldad");
p1.Validate();
try {
p1.middleName = "";
}
catch (err) {
alert(err);
}
let p2 = new Employee("Shahar", "Eldad");
p2.Validate();
document.body.innerHTML = p1.firstName + " " + p2.lastName;
and last my index.html file:
<!DOCTYPE html>
<html>
<head>
<meta charset="windows-1255">
<title>Insert title here</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/require.js/2.3.2/require.min.js" data-main="app.js"></script>
</head>
<body>
</body>
</html>
and last my tsconfig.json file:
{
"compilerOptions": {
"module": "commonjs",
"noImplicitAny": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"target": "es6"
},
"files": [
"app.ts",
"Person.ts"
]
}
I tried at first to transpile with target es5 and then I moved to es6 (and last moved to the tsconfig.json file)
Update
I did like #Louis and it seems to work - copied all files from my question and only edited tsconfig.json to hold amd and es5. I couldn`t see any difference between the before and after the copy. Weird.
Using "module": "commonjs" when you want the output of the TypeScript compiler to be loaded by RequireJS, is definitely wrong. You should use "module": "amd". (You may need to change change your target back to es5 too.)
The error you get is because with "module": "commonjs", the compiler will output code similar to this for your import {Person} from "./Person":
var _Person = require("./Person");
var Person = _Person.Person;
The call to require will cause RequireJS to execute but that will fail because RequireJS does not support such code directly. The code above would work if it is in a define like this:
define(function (require) {
var _Person = require("./Person");
var Person = _Person.Person;
// Rest of the module.
});
When you use "module": "amd", the compiler produces code similar to this snippet and it works.

Categories