首頁 >web前端 >js教程 >無需(建置)工具的 Web 開發

無需(建置)工具的 Web 開發

WBOY
WBOY原創
2024-08-05 19:11:221133瀏覽

Web Development Without (Build) Tooling

當啟動一個將使用 JavaScript 的新 Web 專案時,我們做的第一件事通常是設定建置和開發人員工具。例如最近很紅的Vite。您可能不知道並非所有 JavaScript(Web)專案都需要複雜的建置工具。事實上,正如我將在本文中展示的那樣,現在比以往任何時候都更容易擺脫困境。

使用index.html 檔案建立一個新專案。

<!doctype html>
<html>
  <head>
  </head>
  <body>
    <p>Hello world</p>
  </body>
</html>

如果您使用的是 VS Code,請安裝即時預覽擴充。運行它。這是一個具有即時重新載入功能的簡單檔案伺服器。您可以使用任何檔案伺服器,Python 內建了一個:

python3 -m http.server

我喜歡即時預覽,因為它會在更改文件後自動刷新頁面。

您現在應該能夠從瀏覽器存取您的index.html 檔案並看到“Hello world”。

接下來,建立一個index.js檔:

console.log("Hello world");

export {};

將其包含在您的index.html中:

<script type="module" src="./index.js"></script>

在瀏覽器中開啟開發者控制台。如果您看到“Hello world”,則表示它正在正確載入。

瀏覽器現在支援 ECMAScript 模組。您可以匯入其他檔案以消除其副作用:

import "./some-other-script.js";

或用於出口

import { add, multiply } "./my-math-lib.js";

很酷吧?請參閱上面的 MDN 指南以了解更多資訊。

套餐

您可能不想重新發明輪子,因此您的專案可能會使用一些第三方套件。這並不意味著您現在需要開始使用套件管理器。

假設我們想使用超級結構進行資料驗證。我們不僅可以從我們自己的(本地)檔案伺服器載入模組,還可以從任何 URL 載入模組。 esm.sh 方便地為 npm 上可用的幾乎所有套件提供模組。

當您造訪 https://esm.sh/superstruct 時,您可以看到您被重新導向到最新版本。您可以在程式碼中包含此包,如下所示:

import { assert } from "https://esm.sh/superstruct";

如果您想安全起見,您可以固定版本。

類型

我不了解你,但 TypeScript 寵壞了我(並且讓我變得懶惰)。在沒有類型檢查器幫助的情況下編寫純 JavaScript 感覺就像走鋼索一樣。幸運的是,我們也不必放棄類型檢查。

是時候淘汰 npm 了(儘管我們不會發布它提供的任何程式碼)。

npm init --yes
npm install typescript

您可以在 JavaScript 程式碼上使用 TypeScript 編譯器!對此有一流的支援。建立 jsconfig.json:

{
  "compilerOptions": {
    "strict": true,
    "checkJs": true,
    "allowJs": true,
    "noImplicitAny": true,
    "lib": ["ES2022", "DOM"],
    "module": "ES2022",
    "target": "ES2022"
  },
  "include": ["**/*.js"],
  "exclude": ["node_modules"]
}

現在運行

npm run tsc --watch -p jsconfig.json

並在程式碼中出現類型錯誤。 TypeScript 編譯器應該要抱怨:

/** @type {number} **/
const num = "hello";

順便說一下,你上面看到的評論是 JSDoc。您可以透過這種方式用類型註解您的 JavaScript。雖然它比使用 TypeScript 更冗長一些,但你很快就會習慣它。它也非常強大,只要您不編寫瘋狂的類型(對於大多數項目來說您不應該這樣做),您應該沒問題。

如果您確實需要複雜的類型(助手),您可以隨時在 .d.ts 檔案中新增一些 TypeScript。

JSDoc 是否只是那些陷入大型 JavaScript 專案的人們能夠逐步遷移到 TypeScript 的墊腳石?我不這麼認為! TypeScript 團隊也持續在 JSDoc + TypeScript 中加入出色的功能,例如即將發布的 TypeScript 版本。自動完成功能在 VS Code 中也非常有效。

導入地圖

我們學習瞭如何在不使用建置工具的情況下將外部套件新增到我們的專案中。但是,如果您將程式碼拆分為許多模組,則一遍又一遍地寫出完整的 URL 可能會有點冗長。

我們可以將導入映射新增到我們的index.html的head部分:

<script type="importmap">
  {
    "imports": {
      "superstruct": "https://esm.sh/superstruct@1.0.4"
    }
  }
</script>

現在我們可以簡單地使用
導入這個包

import {} from "superstruct"

就像一個「正常」項目。另一個好處是,如果您在本地安裝該軟體包,類型的完成和識別將按預期工作。

npm install --save-dev superstruct

請注意,node_modules 目錄中的版本將不會被使用。您可以將其刪除,您的專案將繼續運行。

我喜歡使用的一個技巧是添加:

      "cdn/": "https://esm.sh/",

到我的導入地圖。然後,透過 esm.sh 提供的任何項目都可以透過簡單地匯入來使用。例如:

import Peer from "cdn/peerjs";

如果您也想從node_modules中提取類型以進行此類導入的開發,則需要將以下內容添加到jsconfig.json的compilerOptions中:

    "paths": {
      "cdn/*": ["./node_modules/*", "./node_modules/@types/*"]
    },

部署

要部署您的項目,請將所有檔案複製到靜態檔案主機,然後就完成了!如果您曾經參與過舊版 JavaScript 項目,您就會知道更新不到 1-2 年的建置工具的痛苦。透過此項目設置,您將不會遭受同樣的命運。

Testing

If your JavaScript does not depend on browser APIs, you could just use the test runner that comes bundled with Node.js. But why not write your own test runner that runs right in the browser?

/** @type {[string, () => Promise<void> | void][]} */
const tests = [];

/**
 *
 * @param {string} description
 * @param {() => Promise<void> | void} testFunc
 */
export async function test(description, testFunc) {
  tests.push([description, testFunc]);
}

export async function runAllTests() {
  const main = document.querySelector("main");
  if (!(main instanceof HTMLElement)) throw new Error();
  main.innerHTML = "";

  for (const [description, testFunc] of tests) {
    const newSpan = document.createElement("p");

    try {
      await testFunc();
      newSpan.textContent = `✅ ${description}`;
    } catch (err) {
      const errorMessage =
        err instanceof Error && err.message ? ` - ${err.message}` : "";
      newSpan.textContent = `❌ ${description}${errorMessage}`;
    }
    main.appendChild(newSpan);
  }
}

/**
 * @param {any} val
 */
export function assert(val, message = "") {
  if (!val) throw new Error(message);
}

Now create a file example.test.js.

import { test, assert } from "@/test.js";

test("1+1", () => {
  assert(1 + 1 === 2);
});

And a file where you import all your tests:

import "./example.test.js";

console.log("This should only show up when running tests");

Run this on page load:

await import("@/test/index.js"); // file that imports all tests
(await import("@/test.js")).runAllTests();

And you got a perfect TDD setup. To run only a section of the tests you can comment out a few .test.js import, but test execution speed should only start to become a problem when you have accumulated a lot of tests.

Benefits

Why would you do this? Well, using fewer layers of abstraction makes your project easier to debug. There is also the credo to "use the platform". The skills you learn will transfer better to other projects. Another advantage is, when you return to a project built like this in 10 years, it will still just work and you don't need to do archeology to try to revive a build tool that has been defunct for 8 years. An experience many web developers that worked on legacy projects will be familiar with.

See plainvanillaweb.com for some more ideas.

以上是無需(建置)工具的 Web 開發的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn