[TypeScript] Try esbuild
Tags: typescript
Published: 2023-04-12 17:02:32

## 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
```html
<div>
    <div id="message_div"></div>
</div>
<script src="/js/index.page.js"></script>
<script>Page.init("hello");</script>
```

#### index.page.ts
```ts
import { IndexView } from "./index.view";

let view: IndexView;
export function init(message: string) {
    view = new IndexView();
    view.updateMessage(message);
}
```

#### index.view.ts
```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;
    }
}
```
## 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
```

I also can execute it as a JavaScript file.

#### indexbuild.mjs
```js
import * as esbuild from 'esbuild';

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

I can execute this by Node.js.

```
node ./esbuilds/indexbuild.mjs
```

## 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
```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);
  }
})();
```

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

#### index.page.ts
```ts
...
(window as any).init = (message: string) => {
    view = new IndexView();
    view.updateMessage(message);
}
```

#### Index.cshtml
```html
...
<script>init("hello");</script>
```

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

* [[PDF-LIB][Electron][TypeScript] Edit PDF ](https://dev.to/masanori_msl/pdf-lib-electron-typescript-edit-pdf-58hp)

#### global.d.ts
```
declare global {
    interface Window {
        Page: IndexPageApi,
    };
}
export interface IndexPageApi {
    init: (message: string) => void,
}
```

#### tsconfig.json
```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
  }
}
```

#### index.page.ts
```ts
...
window.Page = {
    init(message: string) {
        view = new IndexView();
        view.updateMessage(message);
    }
}
```

#### Index.cshtml
```html
...
<script>Page.init("hello");</script>
```

## Resources
* [esbuild - Getting Started](https://esbuild.github.io/getting-started/)
* [esbuild Not Including JS Functions Called by HTML - StackOverflow](https://stackoverflow.com/questions/68398452/esbuild-not-including-js-functions-called-by-html)
* [How to add live reload to esbuild server - How to dev](https://how-to.dev/how-to-add-live-reload-to-esbuild-server)