iT邦幫忙

2023 iThome 鐵人賽

DAY 19
0
Vue.js

Vue3歡樂套件箱耶系列 第 19

開箱19:所以Import是?陪我一起觀念釐清~

  • 分享至 

  • xImage
  •  

在轉寫框架時,用了很多import,可是卻不知道有區分靜態跟動態導入(dynamic import)?那動態載入跟框架裡面的用法有什麼關係?
/images/emoticon/emoticon06.gif
於是我將很多困惑交給最強顧問chatGPT 4.0,因此有了以下整理:

目錄

  • JavaScript模組系統的歷史背景
  • ES模組(ECMAScript Modules)的import語法
  • 如何區分該用什麼模式導入?
  • 動態導入在不同框架中使用方式
  • Vue3中的defineAsyncComponent跟import()有什麼差別?

JavaScript模組系統的歷史背景

  • 早期JavaScript(無模組系統)
    在早期的JavaScript中,沒有原生的模組系統。開發者通常會將所有的程式碼放在一個或多個<script>於標籤中。這樣做會導致全局作用域污染和命名衝突。
<script src="script.js"></script>
  • 立即調用函數表達式(IIFE)
    為了解決全局作用域污染的問題,開發者開始使用IIFE來模擬模組。
// javascript

(function() {
  // 模組程式碼
})();
  • CommonJS 和 AMD
    Node.js 採用了CommonJS作為其模組系統,這也影響了前端開發。CommonJS 使用 require()module.exports 來導入和導出模組。

  • AMD(Asynchronous Module Definition)則是另一種模組定義標準,主要用於瀏覽器,它支持非同步加載。

  • UMD(Universal Module Definition)
    UMD是一種嘗試統一CommonJS和AMD的模組定義方式。

  • ECMAScript Modules(ESM)
    ECMAScript 2015(也稱為ES6)引入了原生的模組系統。這是第一次JavaScript有了原生的模組支持。ESM使用importexport語句來導入和導出模組。

如果想知道寫法差異,可看此篇
延伸閱讀:
實現AMD的require.js 與 ES6 Import/Export 大比拚


ES模組(ECMAScript Modules)的import語法

分為靜態導入(Static Import)以及動態導入(Dynamic Import)

  1. 靜態導入(使用 import ... from ... 語法)
    靜態導入會在程式啟動時就將所有模組加載進來

基本用法:

import * as myModule from "/modules/my-module.js"; //導入整個模組
import { foo, bar } from "/modules/my-module.js";//導入特定的功能或變數
import { add as addition } from '/modules/my-module.js';//導入並重新命名
import myDefault from "/modules/my-module.js";//導入默認值,引入模塊有一個default export

...等多種寫法

小提醒:
如果是你在HTML引用靜態導入,要加上<script type="module">import ... from ... ;</script>
前往 >> 小試身手

  1. 動態導入(使用import()函式)
    可以在程式運行時(runtime)動態地導入模組

基本用法:
當使用者點擊到才會調用模組的方法,進而做後續處理

const main = document.querySelector("main");
for (const link of document.querySelectorAll("nav > a")) {
  link.addEventListener("click", (e) => {
    e.preventDefault();

    import("/modules/my-module.js") // 動態導入
      .then((module) => {
        // 使用module做一些事情
        module.loadPageInto(main);
      })
      .catch((err) => {
         // 處理錯誤
        main.textContent = err.message;
      });
  });
}
  • 這個函式會回傳一個 Promise,當模組載入完成後,這個 Promise 會解析(resolve)為該模組的導出(exports),所以也可以支持 await寫法

詳細可看
MDN介紹import

如何區分該用什麼模式導入?

/ 用途
靜態導入 用於基本依賴和全局模組,它在編譯時解析。
動態導入 用於需要條件加載或懶加載的模組,它在運行時解析。
  • 靜態導入,用法例如:
import React from 'react';  // 基本依賴
import { add } from './math';  // 自定義模組

簡單來說像是基本的vue,或者組件內使用的套件不太可能是需要動態才載的

  • 動態導入,用法例如:
// 條件加載
if (userIsAdmin) {
  import('./adminModule.js').then(module => module.init());
}

// 懶加載和代碼拆分
button.addEventListener('click', () => {
  import('./dialogBox.js').then(module => module.open());
});

簡單來說可以根據某些條件來決定是否導入某個模組或者你的應用程式非常大時需要按需加載


動態導入在不同框架中使用方式

  • React使用React.lazy()來實現組件的動態導入
const OtherComponent = React.lazy(() => import('./OtherComponent'));
  • Angular的路由(RouterModule)中使用 import() 來實現路由組件的動態導入
const routes: Routes = [
  { path: 'lazy', loadChildren: () => import('./lazy.module').then(m => m.LazyModule) }
];
  • Vue的路由(Vue Router)中使用 import() 來實現路由組件的動態導入
const routes = [
  {
    path: '/dynamic',
    component: () => import('./DynamicRouteComponent.vue'),
  },
];

...當然還有其他出現的場景

若你想知道針對vue路由動態載入跟靜態載入網頁跑起來有什麼差別,可以看
延伸閱讀:
不只懂 Vue 語法:為何懶加載路由和元件會提升網頁效能?


Vue3中的defineAsyncComponent跟import()有什麼差別?

還記得我們在17篇已經介紹過defineAsyncComponent,當時我的需求是,當使用者點擊按鈕打開下面視窗才要載入元件的資源,
以下為範例代碼

<template>
  <div>
    <button @click="show = !show">點我打開視窗</button>
    <dynamicModel v-if="show" />
  </div>
</template>

<script setup>
import { ref,defineAsyncComponent} from 'vue';

const dynamicModel = defineAsyncComponent(() => import('./dynamicModel.vue')); // 動態載入组件

const show = ref(false);
</script>

但是其實寫成

<template>
    // 同上
</template>

<script>
import { ref } from 'vue';

export default {
  components: {
    dynamicModel: () => import('./dynamicModel.vue')
  },
  setup() {
    const show = ref(false);

    return {
      show,
    };
  },
};
</script>

成果都為下,所以我想知道這兩個差異?

(一開始沒載入dynamicModel,打開後才載入)
前往 >> Demo 網址:https://hahasister-ironman-project.netlify.app/#/asyncComponent

而差異是,
import():它是JavaScript的內置功能,用於在運行時動態加載模塊,可以用於任何JavaScript模塊,包括Vue組件。這是異步加載的一種方式,可以實現僅在需要時才加載組件。

defineAsyncComponent():它是Vue 3提供的工具,主要用於定義Vue組件的異步加載方式,且有多種參數可以設定。它簡化了在Vue應用程序中使用import() 動態載入組件的過程,但實質上它使用的還是import()來實現異步加載。

兩者都可以實現異步加載,只是defineAsyncComponent() 提供了一種Vue內置的方式,讓您更容易地在Vue組件中使用import() 進行異步加載。


以上希望大家有一起解到困惑,讓今晚有個好眠
/images/emoticon/emoticon46.gif
那我們明天再見~


上一篇
開箱18:圖片/元件懶加載~vue3 + IntersectionObserver API範例應用
下一篇
開箱20:前端用戶導覽這樣做~v-onboarding範例應用
系列文
Vue3歡樂套件箱耶30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言