[TypeScript] Try esbuild

masanori_msl

Masui Masanori

Posted on April 12, 2023

[TypeScript] Try esbuild

Intro

This time, I will try esbuild to bundle my client-side TypeScript files.
Because I have used Webpack to bundle files, and I will replace them.

Base project

Index.cshtml

<div>
    <div id="message_div"></div>
</div>
<script src="/js/index.page.js"></script>
<script>Page.init("hello");</script>
Enter fullscreen mode Exit fullscreen mode

index.page.ts

import { IndexView } from "./index.view";

let view: IndexView;
export function init(message: string) {
    view = new IndexView();
    view.updateMessage(message);
}
Enter fullscreen mode Exit fullscreen mode

index.view.ts

export class IndexView {
    private messageDiv: HTMLElement;
    public constructor() {
        this.messageDiv = document.getElementById("message_div") as HTMLElement;
    }
    public updateMessage(message: string): void {
        this.messageDiv.textContent = message;
    }
}
Enter fullscreen mode Exit fullscreen mode

Bundling files

I can bundle the TypeScript files by command.
(On Windows, I have to change execution policy to run PowerShell scripts first)

./node_modules/.bin/esbuild ./ts/index.page.ts --bundle --outfile=./wwwroot/js/index.page.js
Enter fullscreen mode Exit fullscreen mode

I also can execute it as a JavaScript file.

indexbuild.mjs

import * as esbuild from 'esbuild';

await esbuild.build({
  entryPoints: ['ts/index.page.ts'],
  bundle: true,
  minify: false,
  outfile: 'wwwroot/js/index.page.js',
});
Enter fullscreen mode Exit fullscreen mode

I can execute this by Node.js.

node ./esbuilds/indexbuild.mjs
Enter fullscreen mode Exit fullscreen mode

Calling functions from outside of TypeScript

After bundling the files, I will get an exception because "Page is not defined".
The bundled file like below.

index.page.js

"use strict";
(() => {
  // ts/index.view.ts
  var IndexView = class {
    constructor() {
      this.messageDiv = document.getElementById("message_div");
    }
    updateMessage(message) {
      this.messageDiv.textContent = message;
    }
  };

  // ts/index.page.ts
  var view;
  function init(message) {
    view = new IndexView();
    view.updateMessage(message);
  }
})();
Enter fullscreen mode Exit fullscreen mode

To call the function from outside of the TypeScript, I should declare them as global.

index.page.ts

...
(window as any).init = (message: string) => {
    view = new IndexView();
    view.updateMessage(message);
}
Enter fullscreen mode Exit fullscreen mode

Index.cshtml

...
<script>init("hello");</script>
Enter fullscreen mode Exit fullscreen mode

Add type declaration

To remove "as any", I will add type declaration files.

global.d.ts

declare global {
    interface Window {
        Page: IndexPageApi,
    };
}
export interface IndexPageApi {
    init: (message: string) => void,
}
Enter fullscreen mode Exit fullscreen mode

tsconfig.json

{
  "compilerOptions": {
    /* Language and Environment */
    "target": "es2016",
    /* Modules */
    "module": "commonjs",
    "baseUrl": "./",
    "paths": {
      "*":["*", "./ts/types/*"]
    },
    /* Emit */
    "noEmit": true,
    /* Interop Constraints */
    "esModuleInterop": true,
    "forceConsistentCasingInFileNames": true,
    /* Type Checking */
    "strict": true,
    "noImplicitAny": true,
    "strictNullChecks": true,
    "strictFunctionTypes": true,
    "strictBindCallApply": true,
    "strictPropertyInitialization": true,
    "noImplicitThis": true,
    "useUnknownInCatchVariables": true,
    "alwaysStrict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "exactOptionalPropertyTypes": true,
    "noImplicitReturns": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "noPropertyAccessFromIndexSignature": true,
    "allowUnusedLabels": true,
    "allowUnreachableCode": true,
    /* Completeness */
    "skipLibCheck": true
  }
}
Enter fullscreen mode Exit fullscreen mode

index.page.ts

...
window.Page = {
    init(message: string) {
        view = new IndexView();
        view.updateMessage(message);
    }
}
Enter fullscreen mode Exit fullscreen mode

Index.cshtml

...
<script>Page.init("hello");</script>
Enter fullscreen mode Exit fullscreen mode

Resources

💖 💪 🙅 🚩
masanori_msl
Masui Masanori

Posted on April 12, 2023

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related