[Client][TypeScript] Try import|export without Webpack
Tags: typescript
Published: 2021-08-03 16:47:45

## Intro
From ES6, I can import|export JavaScript files as modules on client-side.
But I have used Webpack to bundle files and never tried it.

Because I want to know should I keep using Webpack or importing|exporting modules, I will try it.

### Environments
* Node.js ver.16.6.0
* TypeScript ver.4.3.5
* Webpack ver.5.42.0

## import|export modules
I can import and export modules as same as using Webpack.

#### module.page.ts
```ts
import * as second from './secondModule';

export function init(): void {
    second.addMessage();
}
```

#### secondModule.ts
```ts
function addMessage(): void {
    const target = document.getElementById('message_target') as HTMLElement;
    target.textContent = 'Hello World';
}
export { addMessage }
```

But there are some differences.
For example, this samples only can work on web server.
If I open the HTML file as local files, I will get errors because of CORS restrictions.

I have to add "type="module"" in script tags and when I call exported functions from HTML, I must import the module file.

#### index.html
```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>module sample</title>
        <meta charset="utf-8">
    </head>
    <body>
        <div id="message_target"></div>
        <script type="module">
            import { init } from './js/module.page.js';
            init();
        </script>
    </body>
</html>
```

### File not found
In this sample, I got one more exception because "secondModule.js" wasn't found.

I used Express and publish JavaScript files as static files.

#### [Server] index.ts
```ts
...
// To receive JSON value from client-side
app.use(express.json());
// To receive Blob value from client-side
app.use(express.raw());
app.use(express.static('clients/public'));
...
```

* [[Express][TypeScript] Uploading file 1](https://dev.to/masanori_msl/express-typescript-uploading-file-1-1538)

I tried importing the file like "import * as second from './secondModule';".

The file path would look like "localhost:3000/js/secondModule", but I really needed to set the path to "localhost:3000/js/secondModule.js".

So I can import the secondModule.js like below.

#### module.page.ts
```ts
import * as second from './secondModule.js';

export function init(): void {
    second.addMessage();
}
```

If I do that, I should research how to add file extensions automatically when I import module files.

* [Does ES6 import/export need “.js” extension? - Stack Overflow](https://stackoverflow.com/questions/44481851/does-es6-import-export-need-js-extension)

### Using libraries
How about any libraries like "Moment.js"?

Of cource, it won't be compiled and copied into the output directory.
So I have to copy the files by myself.

### Shall I import|export in ES6 way or keep using Webpack?
At least in these samples, I prefer to use Webpack or any other bundling tools.
Because I felt they are more simpler and they can be used in a wider range of environments include IE.

But I'm also interested in import|export of ES6.

## Dynamic import
From ES2020, I can also import modules dynamically.
I don't need adding "type="module"" into the script tag.

#### module.page.ts
```ts
// eslint-disable-next-line @typescript-eslint/no-unused-vars
function init(): void {
    import('./secondModule.js').then(v => v.addMessage());  
}
```
#### index.html
```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>module sample</title>
        <meta charset="utf-8">
        </head>
    <body>
        <div id="message_target"></div>
        <script src="./js/module.page.js"></script>
        <script>init();</script>
    </body>
</html>
```

### Dynamic import with Webpack
I can also use dynamic import in the project what is bundled by Webpack.

#### index.html
```html
<!DOCTYPE html>
<html lang="en">
    <head>
        <title>module sample</title>
        <meta charset="utf-8">
        </head>
    <body>
        <div id="message_target"></div>
        <script src="./js/module.page.js"></script>
        <script>Page.init();</script>
    </body>
</html>
```
#### module.page.ts
```ts
export function init(): void {
    import('./secondModule').then(v => v.addMessage());  
}
```

After compiling, "secondModule.js" is separated from the bundled file.

#### ts_secondModule_ts.js
```js
/*
 * ATTENTION: An "eval-source-map" devtool has been used.
 * This devtool is neither made for production nor for readable output files.
 * It uses "eval()" calls to create a separate source file with attached SourceMaps in the browser devtools.
 * If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
 * or disable the default devtool with "devtool: false".
 * If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
 */
(self["webpackChunkPage"] = self["webpackChunkPage"] || []).push([["ts_secondModule_ts"],{

/***/ "./ts/secondModule.ts":
/*!****************************!*\
  !*** ./ts/secondModule.ts ***!
  \****************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {

"use strict";
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */   \"addMessage\": () => (/* binding */ addMessage)\n/* harmony export */ });\nfunction addMessage() {\r\n    const target = document.getElementById('message_target');\r\n    target.textContent = 'Hello World';\r\n}\r\n\r\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly9QYWdlLy4vdHMvc2Vjb25kTW9kdWxlLnRzPzNkZjQiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7OztBQUFBO0FBQ0E7QUFDQTtBQUNBO0FBQ3NCIiwiZmlsZSI6Ii4vdHMvc2Vjb25kTW9kdWxlLnRzLmpzIiwic291cmNlc0NvbnRlbnQiOlsiZnVuY3Rpb24gYWRkTWVzc2FnZSgpIHtcclxuICAgIGNvbnN0IHRhcmdldCA9IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCdtZXNzYWdlX3RhcmdldCcpO1xyXG4gICAgdGFyZ2V0LnRleHRDb250ZW50ID0gJ0hlbGxvIFdvcmxkJztcclxufVxyXG5leHBvcnQgeyBhZGRNZXNzYWdlIH07XHJcbiJdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///./ts/secondModule.ts\n");

/***/ })

}]);
```

Lazy loading is very useful in some situations.
So I would use it when lazy loading is needed and IE compatibility is not needed :P

## Resources
* [import - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import)
* [export - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export)
* [JavaScript: The Definitive Guide](https://www.oreilly.com/library/view/javascript-the-definitive/9781491952016/)
* [JavaScript modules - JavaScript | MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules)