oblador / react-native-vector-icons

Customizable Icons for React Native with support for image source and full styling.
https://oblador.github.io/react-native-vector-icons/
MIT License
17.31k stars 2.12k forks source link

vector icon not shown in react native for web #1425

Closed aartigehlot closed 11 months ago

aartigehlot commented 2 years ago

Environment

Description

Describe your issue in detail. Include screenshots if needed.

Demo

You can use https://snack.expo.io/ to create a demo that can help users to better understand your problem.

hsavit1 commented 2 years ago

there are not enough steps or details here to warrant an issue. this should be closed

gciluffo commented 2 years ago

I am running into the same issue where the icon is not displaying in RNW with the newest version of react-native-vector-icons: Screen Shot 2022-05-13 at 12 40 07 PM

I have no idea if its related to what @aartigehlot is seeing. Also im not sure if this is an issue related to this library and RNW or webpack config issue.

Here is the repo with the issue reproduced: https://github.com/gciluffo/react-native-web Here is the commit with changes attempting to get icons working in web: https://github.com/gciluffo/react-native-web/commit/80d608a68c79bd368b9bc363fb528c8f9ee296b7

webpack.js.config:

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const appDirectory = path.resolve(__dirname, '../');

const compileNodeModules = [
  'react-navigation',
  '@react-navigation',
  'react-native-uncompiled',
  'react-native-web',
  '@mobily/stacks',
  'react-native-vector-icons',
].map(moduleName => path.resolve(appDirectory, `node_modules/${moduleName}`));

const babelLoaderConfiguration = {
  test: /\.m?[t|j]sx?$/,
  include: [
    path.resolve(__dirname, 'index.web.js'),
    path.resolve(appDirectory, 'src'),
    ...compileNodeModules,
  ],
  use: {
    loader: 'babel-loader',
    options: {
      presets: ['module:metro-react-native-babel-preset'],
      plugins: [['react-native-web']],
    },
  },
};

const svgLoaderConfiguration = {
  test: /\.svg$/,
  loader: '@svgr/webpack',
};
const imageLoaderConfiguration = {
  test: /\.(gif|svg|jpg|png)$/,
  loader: 'file-loader',
};
const ttfLoaderConfig = {
  test: /\.ttf$/,
  loader: 'url-loader', // or directly file-loader
  include: [
    path.resolve(appDirectory, 'node_modules/react-native-vector-icons'),
  ],
};

module.exports = {
  entry: {
    // load any web API polyfills
    // path.resolve(appDirectory, 'polyfills-web.js'),
    // your web-specific entry file
    app: path.join(__dirname, 'index.web.js'),
  },
  // configures where the build ends up
  output: {
    path: path.resolve(appDirectory, 'dist'),
    publicPath: '/',
    filename: 'rnw.bundle.js',
  },
  devServer: {
    historyApiFallback: true,
  },
  resolve: {
    // If you're working on a multi-platform React Native app, web-specific
    // module implementations should be written in files using the extension
    // `.web.js`.
    extensions: ['.web.tsx', '.web.ts', '.tsx', '.ts', '.web.js', '.js'],
    alias: {
      'react-native$': 'react-native-web',
    },
  },
  module: {
    rules: [
      babelLoaderConfiguration,
      imageLoaderConfiguration,
      svgLoaderConfiguration,
      ttfLoaderConfig,
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'index.html'),
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      // See: <https://github.com/necolas/react-native-web/issues/349>
      __DEV__: JSON.stringify(true),
    }),
  ],
};

App.tsx:

/**
 * Sample React Native App
 * https://github.com/facebook/react-native
 *
 * @format
 * @flow strict-local
 */

import React, {useEffect} from 'react';

import {NoteList, NoteDetail} from './screens';
import {StacksProvider} from '@mobily/stacks';
import {NavigationContainer} from '@react-navigation/native';
import {createNativeStackNavigator} from '@react-navigation/native-stack';
import {Platform, Text} from 'react-native';

const Stack = createNativeStackNavigator();

const linking = {
  prefixes: ['http://localhost:8080'],
  config: {
    initialRouteName: 'NoteList' as 'NoteList' | 'NoteDetail' | undefined,
    screens: {
      NoteList: 'notes',
      NoteDetail: 'note-detail/:id',
    },
  },
};

function App() {
  useEffect(() => {
    if (Platform.OS === 'web') {
      const iconFontStyles = `@font-face {
  src: url(${require('react-native-vector-icons/Fonts/FontAwesome.ttf')}) format(truetype);
  font-family: "FontAwesome";
}`;

      // Create stylesheet
      const style = document.createElement('style');
      style.appendChild(document.createTextNode(iconFontStyles));

      // Inject stylesheet
      document.head.appendChild(style);
    }
  }, []);

  return (
    <StacksProvider spacing={4}>
      <NavigationContainer linking={linking} fallback={<Text>Loading...</Text>}>
        <Stack.Navigator>
          <Stack.Screen name="NoteList" component={NoteList} />
          <Stack.Screen name="NoteDetail" component={NoteDetail} />
        </Stack.Navigator>
      </NavigationContainer>
    </StacksProvider>
  );
}

export default App;

When inspecting the DOM I can see that the font-family is included: Screen Shot 2022-05-13 at 12 39 17 PM

Uzef1997 commented 2 years ago

Hi, @gciluffo did you find any solution? I am also running into the same issue please let me know if there is any solution with this

gciluffo commented 2 years ago

@Uzef1997 No. We decided to just use react-native-svg and react-native-svg-transformer for our icons which supports both native and web.

JoshBot-Debug commented 1 year ago

To use react-native-vector-icons with react-native-web

webpack.js.config:

I have commented "ADD THIS LINE HERE" where you need to add a line

const path = require('path');

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

const appDirectory = path.resolve(__dirname);
const {presets} = require(`${appDirectory}/babel.config.js`);

const compileNodeModules = [
  // Add every react-native package that needs compiling
  // 'react-native-gesture-handler',
  'react-native-vector-icons', // ADD THIS LINE HERE
].map((moduleName) => path.resolve(appDirectory, `node_modules/${moduleName}`));

const babelLoaderConfiguration = {
  test: /\.js$|tsx?$/,
  // Add every directory that needs to be compiled by Babel during the build.
  include: [
    path.resolve(__dirname, 'index.web.js'), // Entry to your application
    path.resolve(__dirname, 'App.tsx'), // Change this to your main App file
    path.resolve(__dirname, 'src'),
    ...compileNodeModules,
  ],
  use: {
    loader: 'babel-loader',
    options: {
      cacheDirectory: true,
      presets,
      plugins: ['react-native-web'],
    },
  },
};

const svgLoaderConfiguration = {
  test: /\.svg$/,
  use: [
    {
      loader: '@svgr/webpack',
    },
  ],
};

// ADD THIS LINE HERE (ttfLoaderConfiguration)
const ttfLoaderConfiguration = {
  test: /\.ttf$/,
  loader: 'url-loader', // or directly file-loader
  include: [
    path.resolve(appDirectory, 'node_modules/react-native-vector-icons'),
  ],
};

const imageLoaderConfiguration = {
  test: /\.(gif|jpe?g|png)$/,
  use: {
    loader: 'url-loader',
    options: {
      name: '[name].[ext]',
    },
  },
};

module.exports = {
  entry: {
    app: path.join(__dirname, 'index.web.js'),
  },
  output: {
    path: path.resolve(appDirectory, 'dist'),
    publicPath: '/',
    filename: 'rnw_blogpost.bundle.js',
  },
  resolve: {
    extensions: ['.web.tsx', '.web.ts', '.tsx', '.ts', '.web.js', '.js'],
    alias: {
      'react-native$': 'react-native-web',
    },
  },
  module: {
    rules: [
      babelLoaderConfiguration,
      imageLoaderConfiguration,
      svgLoaderConfiguration,
      ttfLoaderConfiguration, // ADD THIS LINE HERE
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'index.html'),
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      // See: https://github.com/necolas/react-native-web/issues/349
      __DEV__: JSON.stringify(true),
    }),
  ],
};

index.web.js:

import {AppRegistry} from 'react-native';
import {name as appName} from './app.json';
import App from './App';

// ADD THESE LINES BELOW
// This is done for Ionicons, just follow the pattern to add others like materialicons, etc

import Ionicons from 'react-native-vector-icons/Fonts/Ionicons.ttf';

const IoniconsStyles = `@font-face {
  src: url(${Ionicons});
  font-family: Ionicons;
}`;

const style = document.createElement('style');
style.type = 'text/css';

if (style.styleSheet) {
  style.styleSheet.cssText = IoniconsStyles;
} else {
  style.appendChild(document.createTextNode(IoniconsStyles));
}

document.head.appendChild(style);

if (module.hot) {
  module.hot.accept();
}
AppRegistry.registerComponent(appName, () => App);
AppRegistry.runApplication(appName, {
  initialProps: {},
  rootTag: document.getElementById('app-root'),
});

After that, just restart webpack and you're done

junaid7898 commented 5 months ago

After applying above mentioned solution i got this error when i do npm run web **Module not found: Error: Can't resolve 'react-native-vector-icons/Fonts/Ionicons.ttf' Can anybody help me on this?

JoshBot-Debug commented 5 months ago

After applying above mentioned solution i got this error when i do npm run web **Module not found: Error: Can't resolve 'react-native-vector-icons/Fonts/Ionicons.ttf' Can anybody help me on this?

Make sure react-native-vector-icons is installed, if it is installed then try deleting node_modules, package-lock.json, and then run

npm install
junaid7898 commented 5 months ago

After applying above mentioned solution i got this error when i do npm run web **Module not found: Error: Can't resolve 'react-native-vector-icons/Fonts/Ionicons.ttf' Can anybody help me on this?

Make sure react-native-vector-icons is installed, if it is installed then try deleting node_modules, package-lock.json, and then run

npm install

Thank you for helping I tried this solution vector icons were already installed and i deleted node modules and package-lock file but got error the same error but this time I am putting here all the info related to error so that i might get some help.

**ERROR in ./index.web.js 1:266-321 Module not found: Error: Can't resolve 'react-native-vector-icons/Fonts/Ionicons.ttf' in resolve 'react-native-vector-icons/Fonts/Ionicons.ttf' in '/Users/Project' Parsed request is a module using description file: /Project/package.json (relative path: .) aliased with mapping 'react-native-vector-icons': 'react-native-vector-icons/dist' to 'react-native-vector-icons/dist/Fonts/Ionicons.ttf' Parsed request is a module using description file: /Users/Project/package.json (relative path: .) Field 'browser' doesn't contain a valid alias configuration resolve as module looking for modules in /Users/Project/node_modules existing directory /Users/Project/node_modules/react-native-vector-icons using description file: /Users/Project/node_modules/react-native-vector-icons/package.json (relative path: .) using description file: /Users/Project/node_modules/react-native-vector-icons/package.json (relative path: ./dist/Fonts/Ionicons.ttf) no extension Field 'browser' doesn't contain a valid alias configuration /Users/Project/node_modules/react-native-vector-icons/dist/Fonts/Ionicons.ttf doesn't exist .web.tsx Field 'browser' doesn't contain a valid alias configuration /Project/node_modules/react-native-vector-icons/dist/Fonts/Ionicons.ttf.web.tsx doesn't exist .web.ts

Here is my webpack.config.js

 const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const appDirectory = path.resolve(__dirname);
const {presets, plugins} = require(`${appDirectory}/babel.config.js`);
const compileNodeModules = [
  // Add every react-native package that needs compiling
  // 'react-native-gesture-handler',
  'react-native-google-places-autocomplete',
  'react-native-vector-icons',
].map(moduleName => path.resolve(appDirectory, `node_modules/${moduleName}`));

const babelLoaderConfiguration = {
  test: /\.(js|jsx|ts|tsx)$/, // Updated to include .jsx
  // Add every directory that needs to be compiled by Babel during the build.
  include: [
    path.resolve(__dirname, 'index.web.js'), // Entry to your application
    path.resolve(__dirname, 'App.js'), // Updated to .jsx
    path.resolve(__dirname, 'src'),
    path.resolve(__dirname, 'component'),
    ...compileNodeModules,
  ],
  use: {
    loader: 'babel-loader',
    options: {
      cacheDirectory: true,
      presets,
      plugins,
    },
  },
};

const svgLoaderConfiguration = {
  test: /\.svg$/,
  use: [
    {
      loader: '@svgr/webpack',
    },
  ],
};

const imageLoaderConfiguration = {
  test: /\.(gif|jpe?g|png|svg)$/,
  use: {
    loader: 'url-loader',
    options: {
      name: '[name].[ext]',
    },
  },
};

const ttfLoaderConfiguration = {
  test: /\.ttf$/,
  loader: 'url-loader', // or directly file-loader
  include: [
    path.resolve(appDirectory, 'node_modules/react-native-vector-icons'),
  ],
};

const tsLoaderConfiguration = {
  test: /\.(ts)x?$/,
  exclude: /node_modules|\.d\.ts$/, // this line as well
  use: {
    loader: 'ts-loader',
    options: {
      compilerOptions: {
        noEmit: false, // this option will solve the issue
      },
    },
  },
};

module.exports = {
  entry: {
    app: path.join(__dirname, 'index.web.js'),
  },
  output: {
    path: path.resolve(appDirectory, 'dist'),
    publicPath: '/',
    filename: 'rnw.bundle.js',
  },
  resolve: {
    extensions: [
      '.web.tsx',
      '.web.ts',
      '.tsx',
      '.ts',
      '.web.js',
      '.js',
      '.jsx',
      '.web.jsx',
    ],
    alias: {
      'react-native$': 'react-native-web',
      'react-native-vector-icons': 'react-native-vector-icons/dist',
      'react-native-maps': '@preflower/react-native-web-maps',
    },
  },
  module: {
    rules: [
      babelLoaderConfiguration,
      imageLoaderConfiguration,
      svgLoaderConfiguration,
      tsLoaderConfiguration,
      ttfLoaderConfiguration,
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.join(__dirname, 'index.html'),
    }),
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
      __DEV__: JSON.stringify(true),
    }),
  ],
};
JoshBot-Debug commented 5 months ago

It's probably because of this

alias: {
      'react-native$': 'react-native-web',
      'react-native-vector-icons': 'react-native-vector-icons/dist', // I think this line here is the problem
      'react-native-maps': '@preflower/react-native-web-maps',
    },

Because you added an alias for react-native-vector-icons, when you import react-native-vector-icons, it'll use the alias react-native-vector-icons/dist

// This is where Ionicons.ttf exists
import Ionicons from 'react-native-vector-icons/Fonts/Ionicons.ttf';

// Because of the alias, this is where it tries to load it from. Ionicons.ttf does not exist at this path
import Ionicons from 'react-native-vector-icons/dist/Fonts/Ionicons.ttf';