You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Next.js 13默认服务组件中使用StencilJS Web Components遇阻求助

在Next.js 13 App Router服务组件中使用Stencil Web组件的解决方案

问题背景

在Next.js 13 App Router及默认服务组件推出前,可通过_app.tsx中的applyPolyfills+defineCustomElements逻辑加载Stencil Web组件。但切换到App Router后,仅将初始化逻辑封装为客户端组件并导入服务组件时,出现以下报错:

TypeError: Cannot read properties of undefined (reading '$hostElement$')
TypeError: Cannot read properties of undefined (reading '$instanceValues$')

核心原因

服务组件会在服务器端直接输出Web组件标签,而Stencil的初始化逻辑仅在客户端组件的useLayoutEffect中执行。这导致服务器渲染的Web组件标签在浏览器环境初始化完成前就尝试执行依赖浏览器API的逻辑,进而触发未定义属性报错。

解决思路

1. 将Web组件的使用逻辑封装为客户端组件

把Web组件的渲染和初始化逻辑放在同一个客户端组件中,避免服务端直接输出未初始化的Web组件标签:

// components/MyStencilComponent.tsx
'use client';

import { useLayoutEffect } from "react";
import { applyPolyfills, defineCustomElements } from 'path/to/your/stencil-components/loader';

export default function MyStencilComponent() {
  useLayoutEffect(() => {
    applyPolyfills().then(() => {
      defineCustomElements(window);
    });
  }, []);

  return (
    <div>
      <my-component first="Next.js" last="The React Framework"></my-component>
    </div>
  );
}

在服务组件的page.tsx中导入该客户端组件:

// app/page.tsx
import MyStencilComponent from '@/components/MyStencilComponent';

export default function Home() {
  return (
    <main>
      <MyStencilComponent />
    </main>
  );
}

2. 延迟Web组件渲染直到初始化完成

通过状态控制Web组件的渲染时机,确保Stencil初始化完成后再渲染目标组件:

// components/CustomElements.tsx
'use client';

import { useLayoutEffect, useState } from "react";
import { applyPolyfills, defineCustomElements } from 'path/to/your/stencil-components/loader';

const CustomElements = ({ children }: { children: React.ReactNode }) => {
  const [isInitialized, setIsInitialized] = useState(false);

  useLayoutEffect(() => {
    applyPolyfills()
      .then(() => defineCustomElements(window))
      .then(() => setIsInitialized(true));
  }, []);

  return isInitialized ? <>{children}</> : null;
};

export default CustomElements;

在服务组件中用该组件包裹Web组件:

// app/page.tsx
import CustomElements from '@/components/CustomElements';

export default function Home() {
  return (
    <main>
      <CustomElements>
        <my-component first="Next.js" last="The React Framework"></my-component>
      </CustomElements>
    </main>
  );
}

3. 配置Next.js跳过Stencil组件的服务器端处理

在next.config.js中添加配置,告知Next.js不在服务器端处理Stencil组件包,避免解析依赖浏览器API的代码:

// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  experimental: {
    serverComponentsExternalPackages: ['your-stencil-component-package-name'],
  },
};

module.exports = nextConfig;

该配置需结合上述客户端组件的初始化方式使用。

总结

服务组件无法直接使用依赖浏览器API的Web组件,核心解决方向为:

  • 将Web组件的渲染逻辑封装到客户端组件
  • 控制渲染时机,确保初始化完成后再渲染Web组件
  • 配置Next.js避免服务器端处理Stencil组件包

内容的提问来源于stack exchange,提问作者5tormTrooper

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 11:18:20