javascript - 在故事书中用 react native 矢量图标 react native 网络问题

标签 javascript reactjs webpack storybook react-native-web

我使用 React Native Web 创建了一个项目,我得到了适用于 Web 和移动设备的 React Native 图标,故事书除外。我不确定如何告诉故事书 webpack 配置来加载 FontAwesome 字体。我尝试在 preview-head.html 中添加 FontAwesome 但仍然没有显示图标只是一个矩形作为占位符。我想要的是让我的图标显示在故事书 webpack 服务器中。

.storybook/main.js:

const webpack = require('webpack');
const path = require('path');
const rootDir = path.join(__dirname, '..');
module.exports = {
  stories: ['../src/storybook/stories/*.stories.tsx'],
  // addons: ['@storybook/addon-docs', '@storybook/addon-viewport', '@storybook/addon-knobs/', '@storybook/addon-links/', '@storybook/addon-actions/'],
  webpackFinal: async config => {
      config.module.rules.push({
          test: /\.(ts|tsx)$/,
          use: [
              {
                    loader: require.resolve('awesome-typescript-loader'),
                    options: {
                        transpileOnly: true
                    }
              }
          ],
      },
      {
        test: /\.ttf$/,
        loader: 'url-loader', // or directly file-loader
        include: path.resolve(
          __dirname,
          '../node_modules/react-native-vector-icons',
        ),
      }, 
           {
        test: /\.(js|jsx|ts|tsx)$/,
        exclude: /node_modules[/\\](?!react-native|react-native-vector-icons|react-color|react-native-gesture-handler|@react-native-community|react-navigation|@react-navigation\/.*)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              'module:metro-react-native-babel-preset',
              '@babel/preset-env',
              '@babel/preset-flow',
              '@babel/preset-typescript',
            ],
            plugins: [
              '@babel/plugin-proposal-class-properties',
              '@babel/plugin-proposal-object-rest-spread',
              'react-native-web',
            ],
          },
        },
          },
     
    )
    config.plugins.push(
      new webpack.DefinePlugin({
      __DEV__: process.env.NODE_ENV !== 'production',
    }),
    );
      config.resolve.alias = {
      ...(config.resolve.alias || {}),
      'react-native': 'react-native-web',
        '@storybook/react-native': '@storybook/react',
        '@sentry/react-native': '@sentry/react',
        'react-native-maps': 'react-native-web-maps',
        'react-native-gesture-handler/GestureHandler': require.resolve(
        'react-native-gesture-handler/GestureHandler',
        ),
        'react-native-gesture-handler/RNGestureHandlerModule': path.join(
        rootDir,
        'node_modules',
        'react-native-gesture-handler/RNGestureHandlerModule.web.js',
      ),
      './RNGestureHandlerModule': path.join(
        rootDir,
        'node_modules',
        'react-native-gesture-handler/RNGestureHandlerModule.web.js',
      ),
      './GestureHandlerButton': path.join(
        rootDir,
        'node_modules',
        'react-native-gesture-handler',
        'GestureHandlerButton.web.js',
      ),
      './GestureComponents': path.join(
        rootDir,
        'node_modules',
        'react-native-gesture-handler',
        'GestureComponents.web.js',
      ),
      './PlatformConstants': path.join(
        rootDir,
        'node_modules',
        'react-native-gesture-handler',
        'PlatformConstants.web.js',
        ),
      '@utilities': path.resolve(__dirname, '../src/utilities/'),
      '@queries': path.resolve(__dirname, '../src/queries'),
      '@pages': path.resolve(__dirname, '../src/components/pages'),
      '@styled-components': path.resolve(
        __dirname,
        '../src/types/libraries/styled-components.ts',
      ),
      '@hooks': path.resolve(__dirname, '../src/hooks'),
      '@atoms': path.resolve(__dirname, '../src/components/atoms'),
      '@molecules': path.resolve(__dirname, '../src/components/molecules'),
      '@resources': path.join(__dirname, '../src/resources'),
      '@providers': path.resolve(__dirname, '../src/providers'),
      '@enums': path.resolve(__dirname, '../src/enums'),
      '@common': path.resolve(__dirname, '../src/components/common'),
      '@contexts': path.resolve(__dirname, '../src/contexts'),
      '@util': path.resolve(__dirname, '../src/components/util'),
      '@images': path.resolve(__dirname, '../src/assets/images'),
      '@icons': path.resolve(__dirname, '../src/assets/icons'),
      '@fonts': path.resolve(__dirname, '../src/assets/fonts'),
    };
    config.resolve.extensions.push('.ts', '.tsx');
    config.module.rules[0].use[0].options.plugins.push(['react-native-web', { commonjs: true }]);
    return config;
  },
};

.storybook/preview-head.html

<link href="https://fonts.googleapis.com/css?family=Quicksand:400,700" rel="stylesheet">
<style type="text/css">
    @font-face {
        font-family: Quicksand-Bold;
        src: url('https://fonts.gstatic.com/s/a/6bb475d143c61221c4ea174d3c51728268e58b12dbc14600d59020ef8deaaead.ttf');
    }

    @font-face {
        font-family: Quicksand-Regular;
        src: url('https://fonts.gstatic.com/s/a/0f408f35c3679417b5580701f3ac08830ce36535af5a643a2ef5b59e91c3c6b7.ttf');
    }

    @font-face {
        font-family: Lato-Regular;
        src: url('https://fonts.gstatic.com/s/a/a649aaf21573a59079c46db19314fd95648f531e610fa932101f2705616b2882.ttf');
    }

    @font-face {
        font-family: Lato-Bold;
        src: url('https://fonts.gstatic.com/s/a/407592da08cb1f6060fbc69262ad33edd0b61ec9160521455eca8f726bbd4353.ttf');
    }
</style>
<script>
    import FontAwesome from '../node_modules/react-native-vector-icons/FontAwesome.js';
    // Generate required css
        import {iconFont} from '../node_modules/react-native-vector-icons/Fonts/FontAwesome.ttf';
        const iconFontStyles = `@font-face {
  src: url(${iconFont});
  font-family: FontAwesome;
}`;

        // Create stylesheet
        const style = document.createElement('style');
        style.type = 'text/css';
        if (style.styleSheet) {
            style.styleSheet.cssText = iconFontStyles;
        } else {
            style.appendChild(document.createTextNode(iconFontStyles));
        }

        // Inject stylesheet
        document.head.appendChild(style);

        try {
                FontAwesome.loadFont();
                console.log("working!");
            } catch (e) {
                console.log(e);
            }
</script>

包.json

"storybook:web": "start-storybook -p 6006"

我认为问题存在于 preview-head.html 中,我知道我不能在脚本标签中使用导入模块,但不确定还有什么地方可以加载 fontAwesome 以便 storybook 可以选择它。谢谢!

最佳答案

recommended approach自从回答了这个问题后,使用 Storybook 的 React Native 已经发生了变化。因此,如果您使用 @storybook/addon-react-native-web 让 Storybook 在浏览器中运行,下面是我如何让自定义字体工作。

我创建了以下 FontLoader 组件,它环绕着我的应用程序的提供程序树。因此,对于 Storybook,我将加载器添加到 .storybook/preview.js 中的全局装饰器中。 (需要说明的是,我没有任何特殊的 webpack 配置。)

// FontLoader.tsx
import React, { PropsWithChildren, useCallback } from 'react'
import { View } from 'react-native'
import { useFonts } from 'expo-font'
import { theme, fontName } from '@theme'

interface Props extends PropsWithChildren {
  onFontsLoaded?: () => void // callback for displaying the splash screen once background view has loaded
}

export const FontLoader = ({ onFontsLoaded, children }: Props) => {
  const [fontsLoaded] = useFonts({
    [fontName]: require('../../assets/fonts/Inter-Regular.otf'),
    'inter-italic': require('../../assets/fonts/Inter-Italic.otf'),
    'inter-light': require('../../assets/fonts/Inter-Light.otf'),
    'inter-medium': require('../../assets/fonts/Inter-Medium.otf'),
    'inter-bold': require('../../assets/fonts/Inter-Bold.otf'),
    'inter-black': require('../../assets/fonts/Inter-Black.otf'),
  })

  const onLayoutRootView = useCallback(async () => {
    if (fontsLoaded) {
      onFontsLoaded?.()
    }
  }, [fontsLoaded, onFontsLoaded])

  if (!fontsLoaded) {
    return null
  }

  return (
    <View onLayout={onLayoutRootView} style={{ flex: 1, backgroundColor: theme.colors.$background }}>
      {children}
    </View>
  )
}
// .storybook/preview.js
import React from 'react'

import { FontLoader } from '../src/utils/FontLoader'
import { ThemeProvider } from '../src/theme'

export const parameters = {
  actions: { argTypesRegex: '^on[A-Z].*' },
  controls: {
    matchers: {
      color: /(background|color)$/i,
      date: /Date$/,
    },
  },
}

export const decorators = [
  Story => (
    <FontLoader>
      <ThemeProvider>
        <Story />
      </ThemeProvider>
    </FontLoader>
  ),
]

关于javascript - 在故事书中用 react native 矢量图标 react native 网络问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/64346044/

相关文章:

javascript - 刷新数据表错误

javascript - 从 responseText 中获取特定的 div 内容并将源代码保存到数据库中

javascript - 在 ES6 React 类的函数中返回变量或常量

html - 防止 <td> 中的 <em> 标签改变高度

javascript - Webpack 多入口点混淆

webpack - 无法让 webpack 热模块更换工作

javascript - 如何在 JavaScript 中使用键值作为变量名?

javascript - JSON.parse() 不适用于 jQuery 数据对象

javascript - 处理两个完全独立的 React 组件之间的数据

vue.js - 无法解析后台 url(...)