查看原文
其他

【第2888期】使用Svelte来构建Web Component

红薯 前端早读课 2023-03-20

前言

火星甘博阿陨击坑。周末愉快,来一篇实践的。今日前端早读课文章由 @红薯翻译,公号:OSC 开源社区分享。

正文从这开始~~

每个开发人员都应该关注代码中的可重用性以及代码的业务隔离,这样可以让业务逻辑与应用架构分离,提升系统的扩展性。而 Web Component 就是这样一个技术,可以让我们创建一个独立的可重用组件。

本文将介绍使用 Svelte 创建通用的 Web Component 的完成过程。『通用』指的是该组件不局限于 Svelte 应用,还可以用于任何 JavaScript 应用程序(如 Vue、React 等),同时还将介绍使用 Svelte 创建 Web Component 的一些局限性。

【第2821期】Web Component入门

什么是 Web Component?

Web Component 可以让我们创建可重用的、自定义的封装了样式以及功能的 HTML 元素。
例如,我们使用如下代码来创建一个导航条:

<style>
/* CSS code for our navbar */
</style>
<navbar>
<!-- Some long code for our navbar -->
</navbar>

如果用 Web Component 技术,我们可以定义一个自定义元素(如 <custom-navbar/>),然后你可以在网页任一地方使用该元素显示导航条,同时这个导航条的样式和页面其他元素的样式是完全隔离的,不会相互影响。而这项技术被称之为 Shadow DOM (影子 DOM)。

什么是 Shadow DOM?

Shadow DOM 是一个较小的、独立的 DOM,它与主 DOM 分开渲染,允许我们将样式和标记行为隔离到单个组件中。Shadow DOM 本质上允许我们将组件功能进行封装和隔离,我们可以单独对其设置样式、编写功能脚本,而不会干扰应用程序的其余元素。

你大概对 Web Component 有一个基本的认识,下面我们开始用 Svelte 来编写一个简单的组件。

【早知】component-party:一个比较不同框架的语法网站

构建 Web Component

准备工作

为了完成本文剩余的内容学习,需要你对掌握以下知识:

  • 对 HTML, CSS 和 JavaScript 有基本的认识

  • 熟悉命令行操作环境

  • 需要一个文本编辑器

  • 最好对 Svelte 有一些基本的了解

开始

本文我们将开发两个组件:

  • 第一个组件是一个卡片组件,接收三个属性分别是:卡片标题、卡片描述以及图片,该组件名为 <my-card />

  • 第二个组件是一个带样式的按钮,接收一个 type 的属性,通过该属性来确定按钮的显示样式,组件名称为 <cool-button />

同时我们将使用两种组件的发布方式,一个是打包到单一文件,另外一个是每个组件发布到一个独立的文件中。

下图显示的是两个组件运行后的外观:

我们从创建一个 Svelte 应用开始,并安装必须的包:

npx degit sveltejs/template web-component-tut
cd web-component-tut
npm install

上述命令执行完毕就可以使用如下命令启动一个测试环境:

npm run dev

然后我们打开浏览器访问 http://localhost:8080 就可以看到一个最基础的 Svelte 应用运行起来后的样子:

开发一个组件

使用 Svelte 生成通用 Web Component 的过程类似于创建常规 Svelte 组件的过程,只是进行了一些修
改。

为了创建第一个卡片组件,我们首先创建一个文件 src/Card.svelte 并定义组件的属性、样式以及 HTML 标签,代码如下:

<script>
// component props
// Camel case not supported for props, see drawback section.
export let card_title, card_desc, card_img;
</script>

<main>
<div class="card-container">
<di vclass="card">
<img src={card_img}alt="My product"/>
<div class="card-body">
<div class="row">
<div class="card-title">
<h2>{card_title}</h2>
</div>
</div>
<p>
{card_desc}
</p>
<button>Do Something</button>
</div>
</div>
</div>
</main>

<style>
.card{
max-width:350px;
border-radius:5px;
box-shadow:04px6px0#00000033;
padding:0010px0;
}

.cardimg{
width:100%;
height:auto;
}

.card-body{
padding:5px10px;
}

.card-bodyp{
color:#575757;
margin-bottom:20px;
font-size:14px;
}
</style>

你可以在其他组件中使用这个卡片组件,如下所示(这一步可忽略):

<script>
import Card from "./Card.svelte";
</script>

<main>
<Card
card_title="My Card Title"
card_desc="Lorem ipsum dolor…"
card_img="path/to/my-image.png"
/>

</main>

接下来是按钮组件,文件名 /src/Button.svelte 代码如下:

<script>
// Component props
export let type ="solid";
</script>

<button class={type=="solid" ? "btn-solid":"btn-outline"}>
<slot/>
</button>

<style>
button{
padding:10px;
color:#fff;
font-size:17px;
border-radius:5px;
border:1px solid #ccc;
cursor: pointer;
}
.btn-solid{
background:#20c997;
border-color:#4cae4c;
}
.btn-outline{
color:#20c997;
background: transparent;
border-color:#20c997;
}
</style>

该组件的使用方法如下(可忽略):

import Button from"./Button.svelte";

<Button type="outline">Click me</Button>

将自定义组件转成通用组件

我们需要将自定义 Svelte 组件转成通用的 Web Component ,这样才可以在其他框架中直接使用。

要做这个转换操作,我们需要在 Svelte 配置文件中设置让编译器生成自定义元素。打开 rollup.config.js 在 plugins 增加一个 compilerOptions 配置项,在该配置项下增加 customElement: true 配置信息,如下所示:

...
plugins:[
svelte({
compilerOptions:{
dev:!production,
customElement:true,
...

然后我们需要给两个组件分别定义一个元素名称,打开 Card.svelte 文件,在文件开头第一行插入如下内容:

<svelte:options tag="my-card"/>

上述 tag 属性值代表组件的标签名称。

同样的,打开 Button.svelte 给第二个组件指定一个标签名称:

<svelte:options tag="cool-button"/>

最后一步是在 main.js 中引入这两个组件,打开 /src/main.js 将里面的内容替换成如下两行:

import Button from"./Button.svelte";
import Card from"./Card.svelte";

这里我们已经完成了两个组件的开发步骤,下一步就是打包组件以便其他的应用可以使用这两个组件,打开命令行窗口进入项目所在目录执行如下命令:

npm run build

该命令将生成两个文件,分别是 build.js 和 build.map.js, 文件位于项目下的 /build 目录。其中 build.js 是打包的两个组件,而 build.map.js 是 build.js 源代码映射文件。

如果上述步骤顺利完成,我们就可以将 bundle.js 拷贝到一个新目录,然后创建一个 index.html 文件,内容如下:

<!DOCTYPE html>
<html>
<head>
<title>My website</title>
<script src="./build.js"></script>
</head>

<body>
<div class="container">
<div class="row">
<div class="col">
<my-card
card_title="Red Person"
card_desc=" Lorem ipsum dolor sit, amet consectetur.."
card_img="https://bit.ly/34B3zHX"
>
</my-card>
<!-- Image credit - Shubham Dhage on unsplash.com -->
</div>
<div class="col">
<div class="border-bottom py-5">
<cool-button> Solid Cool Button </cool-button>
<cool-buttontype="outline"> Outlined Cool Button </cool-button>
</div>
</div>
</div>
</div>
</body>
</html>

这是一个再简单不过的 HTML 页面了,该页面使用了上述两个组件,在浏览器中显示为如下效果:

组件分割

在某些情况下我们不需要将多个组件打包到同一个 js 文件中,我们希望每个组件有一个独立的 js 文件。要实现这个场景只需在 rollup.config.js 的 input 和 output 中进行配置即可。

在 input 的配置中我们可以指定一个数组,数组的元素就是每个组件的文件路径,而 output 指定为输出的目录即可:

export default{
input:["src/Card.svelte","./src/Button.svelte"],
output:{
format:"iife",
dir:"public/build/",
},
...

修改完成后再次执行 npm run build ,我们就可以在 build 目录中看到两个文件 Button.js 和 Card.js 。

使用方法类似:

<script src="Button.js"type="module"></script>
<cool-button type="outline">Click Me</cool-button>

<!-- another-page.html -->
<script src="Card.js"type="module"></script>
<my-card card_title="..."></my-card>

主要缺点

到这里我们已经掌握了使用 Svelte 开发 Web Component 的方法,这个过程非常之简单,但是,使用 Svelte 开发 Web 组件会有一些缺点如下:

  • 组件的属性名称不允许使用驼峰命名法,例如你会发现使用形如 cardTitle 这样的属性名就无法正常工作,而驼峰命名法又是 JavaScript 推荐的命名风格。这是一个 Bug,不过如果你使用的是 Vite ,那么有一个 workaround plugin 可以解决这个问题。

  • 如果不标记 Web 组件,就无法在 Svelte 中重用它们 - 不幸的是,您还必须标记要在自定义 Web 组件中使用的每个 Svelte 组件

  • 加入你有一个 Header.svelte 文件需要作为 <my-header /> 组件输出,但同时这个组件又依赖另外一个 Nav.svelte 文件,而 Nav.svelte 我们不希望作为 Web 组件输出,这个问题使得我们必须将 Nav.svelte 也作为组件输出,否则程序就会报错。好在这个问题现在也有解了(详情请看 https://github.com/svelte-society/recipes-mvp/issues/41#issue-638005462),我们可以通过配置来解决这个问题,虽然看起来不是那么的爽,就这样吧,又不是不能用。

  • 浏览器的支持问题 — JavaScript customElement API 就是用来创建 Web Component 的底层 API,该 API 目前并没有被所有的浏览器支持,我们需要引入 Polyfill 来解决这个文件,详情请看 https://github.com/webcomponents/polyfills/tree/master/packages/custom-elements。

总结

在本文中,我们学习了如何使用 Svelte 创建通用卡片和按钮组件,生成捆绑文件,拆分它们,甚至在单独的 HTML 页面中重用此组件。

动手试试吧?

【第2769期】重磅!哈啰 Quark Design 正式开源,新一代跨技术栈前端组件库

关于本文
译者:@红薯
译文:https://mp.weixin.qq.com/s/a-Zsgrrj3VsxEiaZWYeh-A
作者:@Elijah Asaolu
原文:https://blog.logrocket.com/build-web-components-svelte/

这期前端早读课
对你有帮助,帮” 
 “一下,
期待下一期,帮”
 在看” 一下 。

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存