NervJS / taro

开放式跨端跨框架解决方案,支持使用 React/Vue/Nerv 等框架来开发微信/京东/百度/支付宝/字节跳动/ QQ 小程序/H5/React Native 等应用。 https://taro.zone/
https://docs.taro.zone/
Other
35.34k stars 4.77k forks source link

Template `tmpl_0_View` not found. #12090

Closed ccqgithub closed 2 years ago

ccqgithub commented 2 years ago

相关平台

微信小程序

复现仓库

https://github.com/ccqgithub/taro-bug-repo.git 小程序基础库: 2.12.3 使用框架: Vue 3

复现步骤

使用vue3 setup导入组件

<script setup lang="ts">
import { View } from '@tarojs/components'
import './index.scss'
import Counter from '../../components/Counter.vue'
</script>

<template>
  <View class="index">
    <Counter />
  </View>
</template>

报错:

[WXML Runtime warning] ./base.wxml
 Template `tmpl_0_View` not found.
  83 | 
  84 | <template name="tmpl_0_container">
> 85 |   <template is="{{xs.a(0, i.nn, l)}}" data="{{i:i,cid:0,l:xs.f(l,i.nn)}}" />
     |                ^
  86 | </template>
  87 | 
  88 | <template name="tmpl_1_catch-view">

如果直接使用模版,element类型不正确,view被当成svg元素了

image

期望结果

  1. setup模式,import的组件能在template中使用
  2. 非setup模式,view元素类型提示正确

实际结果

报错

环境信息

Taro CLI 3.4.13 environment info:
    System:
      OS: macOS 12.4
      Shell: 5.8.1 - /bin/zsh
    Binaries:
      Node: 16.15.1 - /usr/local/bin/node
      npm: 8.11.0 - /usr/local/bin/npm
    npmPackages:
      @tarojs/components: 3.4.13 => 3.4.13 
      @tarojs/mini-runner: 3.4.13 => 3.4.13 
      @tarojs/runtime: 3.4.13 => 3.4.13 
      @tarojs/taro: 3.4.13 => 3.4.13 
      @tarojs/webpack-runner: 3.4.13 => 3.4.13 
      babel-preset-taro: 3.4.13 => 3.4.13 
      eslint-config-taro: 3.4.13 => 3.4.13 
Chen-jj commented 2 years ago

@ccqgithub Vue 中 Taro 内置组件需要小写:<view>,Demo 对 <View> 的使用里是 Taro React 的用法,是不对的。

另外类型提示是怎么出现的?

ccqgithub commented 2 years ago

@ccqgithub Vue 中 Taro 内置组件需要小写:<view>,Demo 对 <View> 的使用里是 Taro React 的用法,是不对的。

vue3 setup 是可以用<View>的,以后基本上都是用这种写法,最好能支持这种写法哦:https://vuejs.org/api/sfc-script-setup.html#using-components

另外类型提示是怎么出现的?

直接用小写<view>就有这个类型提示,因为view在vue本身的定义里是svg的子元素。除了<view>之外,小写的标签很多类型提示都不正确,比如<scroll-view>

下面我的解决方案,现在是每个组件自己封装了一层使用,对taro的代码不是很熟,无法提PR,供参考

import { FunctionalComponent, CSSProperties, h } from 'vue';
import {
  View,
  ViewProps,
  ScrollView,
  ScrollViewProps,
  Image,
  ImageProps,
  Text,
  TextProps,
  Button,
  ButtonProps,
  Input,
  InputProps,
  WebView,
  WebViewProps,
  Textarea,
  TextareaProps,
  BaseEventOrig,
  StandardProps
} from '@tarojs/components';

export type {
  ViewProps,
  ScrollViewProps,
  ImageProps,
  TextProps,
  StandardProps,
  ButtonProps,
  InputProps,
  TextareaProps,
  WebViewProps,
  BaseEventOrig
};

type LowercaseKeys<O extends Record<string, any>> = {
  [K in keyof O as Lowercase<string & K>]: O[string & K];
};

// get event keys from props
// { onClick: FN } => ['click']
type EventKeys<T> = NonNullable<
  {
    [K in keyof T]: K extends `on${infer E}` ? Uncapitalize<E> : never;
  }[keyof T]
>;

// filter event properties
// { onClick: FN, other: any } => { click: FN }
type Events<T extends Record<string, any>> = {
  [Key in EventKeys<T>]: Required<T>[`on${Capitalize<Key>}`];
};

// props => emits
// { onClick: FN } => { click: FN, tap: FN }
type PropsToEmits<P extends Record<string, any>> = Required<Events<P>>;

// https://github.com/NervJS/taro/blob/next/packages/taro-components/types/index.vue3.d.ts
// 联合类型不能用omit(比如picker)
type DistributiveOmit<T, K extends keyof T> = T extends unknown
  ? Omit<T, K>
  : never;

type SlimProps = {
  class?: any;
  style?: CSSProperties;
  innerHTML?: string;
  // setRef?: (el: Element | null) => void;
};

/** 转换react的类型到vue */
type RemoveReactAttribute =
  | 'className'
  | 'style'
  | 'key'
  | 'ref'
  | 'dangerouslySetInnerHTML';

export type TransformReact2VueType<
  P extends Record<string, any> = Record<string, any>
> = DistributiveOmit<P, RemoveReactAttribute> & {
  onTap?: P['onClick'];
} & SlimProps;

const createComponent = <
  P extends Record<string, any>,
  T = TransformReact2VueType<P>
>(
  tag: any
) => {
  return ((props, ctx) => {
    return h(tag, { ...props, ...ctx.attrs }, ctx.slots);
  }) as FunctionalComponent<T, LowercaseKeys<PropsToEmits<P>>>;
};

export * from './NPageMeta';
export const NView = createComponent<ViewProps>(View);
export const NImage = createComponent<ImageProps>(Image);
export const NText = createComponent<TextProps>(Text);
export const NScrollView = createComponent<ScrollViewProps>(ScrollView);
export const NButton = createComponent<ButtonProps>(Button);
export const NInput = createComponent<InputProps>(Input);
export const NTextArea = createComponent<TextareaProps>(Textarea);
export const NWebView = createComponent<WebViewProps>(WebView);
qsjc commented 2 years ago

未使用ts的demo没发现这个问题

Chen-jj commented 2 years ago

@ccqgithub

vue3 setup 是可以用的,以后基本上都是用这种写法,最好能支持这种写法哦:https://vuejs.org/api/sfc-script-setup.html#using-components

Vue 组件才可以大写,<view> 相当于 H5 的 <div>,属于原生标签是不可以的。

直接用小写就有这个类型提示,因为view在vue本身的定义里是svg的子元素。除了之外,小写的标签很多类型提示都不正确,比如

感觉是不是装了什么 VSCode 插件后提供的类型提示,你可以点进去类型跟踪是哪个文件导出的类型。目测是一个全局类型,那么你可以通过 TS 的模块补全去修改这个全局类型来解决。

ccqgithub commented 2 years ago

@ccqgithub

vue3 setup 是可以用的,以后基本上都是用这种写法,最好能支持这种写法哦:https://vuejs.org/api/sfc-script-setup.html#using-components

Vue 组件才可以大写,<view> 相当于 H5 的 <div>,属于原生标签是不可以的。

直接用小写就有这个类型提示,因为view在vue本身的定义里是svg的子元素。除了之外,小写的标签很多类型提示都不正确,比如

感觉是不是装了什么 VSCode 插件后提供的类型提示,你可以点进去类型跟踪是哪个文件导出的类型。目测是一个全局类型,那么你可以通过 TS 的模块补全去修改这个全局类型来解决。

不是插件的问题,这是vue 的类型提示,原因是vue是针对web标准开发的,所以它内置的类型都是正当html标签的。当小程序的标签跟html的标签重叠但是功能不一样时,就会有问题。

react如果直接使用标签不使用组件的话应该也会有类似的问题。

重新定义vue的类型提示可是可以就是比较麻烦,react可以用组件的方式解决,是不是vue也可以呢?

Richard-Choooou commented 2 years ago

遇到一样的问题,很糟心

yijinc commented 2 years ago

遇到类似错误,我是

<template>
  <Navbar hideBack />
  <view :class="styles.container">
    <text>{{ greeting }}</text>
    <Button type="primary" >nutui</Button>
  </view>
</template>

<script lang="ts" setup>
import Navbar from '@/components/navbar';
import { Button } from "@nutui/nutui-taro";
import styles from './styles.scss';

const greeting = 'Hello world';

</script>

button 渲染不出来,控制台警告错误:

[WXML Runtime warning] ./base.wxml
Template `tmpl_0_Button` not found.
<template name="tmpl_1_container">
Chen-jj commented 2 years ago

@yijinc Button 是内置组件,改为 NutButton 吧:import { Button as NutButton } from "@nutui/nutui-taro"

Chen-jj commented 2 years ago

在开启了 Volar 等开发者工具插件后,Vue SFC template 能够得到类型提示。原问题修改全局的 IntrinsicElements 可以解决, @ZakaryCode 有空可以看看

import {
  ViewProps
} from '@tarojs/components'

declare global {
  namespace JSX {
    interface IntrinsicElements {
      view: ViewProps
    }
  }
}
loonyzhang commented 2 years ago

@ZakaryCode 解决了? 我这边 windows 3.5.4版本还是有这个问题

ZakaryCode commented 2 years ago

@ZakaryCode 解决了? 我这边 windows 3.5.4版本还是有这个问题

PR 还没有合入,等下一个版本咯

Alex20180512 commented 1 year ago

3.6.5 版本开启 webpack5 的 cache 功能稳定复现,关了就好了

lihuangshuaige commented 1 year ago

看了半天 没看懂咋解决啊