https://developer.mozilla.org/en-US/docs/Glossary/IIFE An IIFE (Immediately Invoked Function Expression) is a JavaScript function that runs as soon as it is defined. Immediately Invoked Function Expression (IIFE) 是 JavaScript 中的一种常见的设计模式,它是一个立即执行的匿名函数表达式。IIFE 通常用于创建一个独立的作用域,避免变量污染全局作用域。 ```js (function () { // … })(); (() => { // … })(); (async () => { // … })(); ``` IIFE is usually used to create a separate scope to avoid polluting the global scope. In this blog I will instead talk about the use of IIFE in hosting web pages. Traditionally, static websites are compiled into an `index.html` file as an entrypoint. css and js files are linked in the `head` and `body` tags. Here is an example of a simple `index.html` file: ```html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8" /> <link rel="icon" type="image/svg+xml" href="/vite.svg" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>Vite + Vue + TS</title> <script type="module" crossorigin src="/assets/index-D7F47PqG.js"></script> <link rel="stylesheet" crossorigin href="/assets/index-DRBiz0Jz.css" /> </head> <body> <div id="app"></div> </body> </html> ``` You can see that in such a client-side rendered web page, the HTML file doesn't contain any content. The content is rendered by the JavaScript file linked in the `head` tag. The `index.html` is only used as a container for the JavaScript file. The JavaScript file is responsible for rendering the content of the web page. Theoretically, we can ship a single JavaScript file contains all the logic and content of the web page (including styles and images (png doesn't work, but svg does)).; ## Vite Config For example, this is the original `vite.config.ts` file for a vue project: ```ts import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], }); ``` Output `dist` folder: ``` dist ├── assets │ ├── Vue.js_Logo_2.svg-BtIZHRhy.png │ ├── index-CjgLCVzZ.css │ └── index-CwnRthTM.js ├── index.html └── vite.svg ``` Next, set output format to `iife` ```ts import { defineConfig } from "vite"; import vue from "@vitejs/plugin-vue"; import path from "path"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], build: { emptyOutDir: false, rollupOptions: { input: path.resolve(__dirname, "./src/main.ts"), output: { format: "iife", dir: path.resolve(__dirname, "./dist"), entryFileNames: "web.js", }, }, }, }); ``` ``` dist ├── assets │ └── Vue.js_Logo_2.svg-BtIZHRhy.png ├── vite.svg └── web.js ``` Now how to use the `web.js` without an `index.html` file? Let's serve the `dist` folder with a simple http server: ```bash serve dist --cors ``` The `web.js` is at `http://localhost:3000/web.js` In an HTML file, ```html <!DOCTYPE html> <html lang="en"> <body> <iframe></iframe> <script> fetch("http://localhost:3000/web.js", { method: "GET", }) .then((res) => res.text()) .then((data) => { document .querySelector("iframe") .contentDocument.write( "<div id='app'/><script>".concat(data, "<\/script>") ); }); </script> </body> </html> ``` Here we are rendering the content of `web.js` in an `iframe`. It can also render the page directly as long as there is a `<div id="app" />`. ```html <!DOCTYPE html> <html lang="en"> <body> <script> fetch("http://localhost:3000/web.js", { method: "GET", }) .then((res) => res.text()) .then((data) => { document.write( "<div id='app'></div><script>".concat(data, "<\/script>") ); }); </script> </body> </html> ``` This is because the `main.ts` is like this ```ts import { createApp } from "vue"; import "./style.css"; import App from "./App.vue"; createApp(App).mount("#app"); ``` So what can be the use case of this? - The key benefit is that the website content doesn't have be to hosted on a server. It can be saved in a database and fetched by the client like a function.