I need to load a local SVG calling as a string './MySvg.svg', but it just works if i call it as a component, like <MySvg />.
I followed this tutorial https://blog.logrocket.com/how-to-use-svgs-in-react/, installed file-loader but the problem persists.
I'm trying to put a custom svg on the nodes of a graph with react-d3-graph, but it needs the svg locally as string and will not accept as a component.
Svgteste just exports the svg tag of svgFile.svg
An example with a component
import * as React from 'react';
import { PageSection, Title } from '#patternfly/react-core';
import { Svgteste } from './Svgteste'
import { Test } from './svgFile.svg'
const Dashboard: React.FunctionComponent = () => {
return(
<PageSection>
<Svgteste /> {/*this works*/}
<img src={'./svgFile.svg'} /> {/*this won't work*/}
<img src={Test} /> {/*neither this*/}
</PageSection>
)
}
export { Dashboard };
My webpack
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin');
const Dotenv = require('dotenv-webpack');
const BG_IMAGES_DIRNAME = 'bgimages';
module.exports = env => {
return {
entry: {
app: path.resolve(__dirname, 'src', 'index.tsx')
},
module: {
rules: [
{
test: /\.(tsx|ts|jsx)?$/,
use: [
{
loader: 'ts-loader',
options: {
transpileOnly: true,
experimentalWatchApi: true,
}
}
]
},
{
test: /\.(svg|ttf|eot|woff|woff2)$/,
// only process modules with this loader
// if they live under a 'fonts' or 'pficon' directory
use: {
loader: 'file-loader',
options: {
// Limit at 50k. larger files emited into separate files
limit: 5000,
outputPath: 'fonts',
name: '[name].[ext]',
}
}
},
{
test: /\.svg$/,
include: input => input.indexOf('background-filter.svg') > 1,
use: [
{
loader: 'url-loader',
options: {
limit: 5000,
outputPath: 'svgs',
name: '[name].[ext]',
}
}
]
},
{
test: /\.svg$/,
// only process SVG modules with this loader if they live under a 'bgimages' directory
// this is primarily useful when applying a CSS background using an SVG
include: input => input.indexOf(BG_IMAGES_DIRNAME) > -1,
use: {
loader: 'svg-url-loader',
options: {}
}
},
{
test: /\.svg$/,
// only process SVG modules with this loader when they don't live under a 'bgimages',
// 'fonts', or 'pficon' directory, those are handled with other loaders
include: input => (
(input.indexOf(BG_IMAGES_DIRNAME) === -1) &&
(input.indexOf('fonts') === -1) &&
(input.indexOf('background-filter') === -1) &&
(input.indexOf('pficon') === -1)
),
use: {
loader: 'raw-loader',
options: {}
}
},
{
test: /\.(jpg|jpeg|png|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 5000,
outputPath: 'images',
name: '[name].[ext]',
}
}
]
},
{
test: /\.svg$/,
use: ['#svgr/webpack'],
},
{
test: /\.(png|jp(e*)g|svg|gif)$/,
use: [
{
loader: 'file-loader',
options: {
//name: 'images/[hash]-[name].[ext]',
},
},
],
},
]
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'src', 'index.html')
}),
new Dotenv({
systemvars: true,
silent: true
})
],
resolve: {
extensions: ['.js', '.ts', '.tsx', '.jsx'],
plugins: [
new TsconfigPathsPlugin({
configFile: path.resolve(__dirname, './tsconfig.json')
})
],
symlinks: false,
cacheWithContext: false
}
}
};
I think, you have to remove the curly braces in the import. The curly braces indicate that you want to import a component that is exported with the given name, which is not the case when you import an svg.
import Test from './svgFile.svg'
Related
Storybook used to crash because I use aliases defined in webpack. I thus modified the main.js config of Storybook to add them manually. When launching the build, Storybook crashes with the following error:
Unexpected token r in JSON at position 27
Here is the config:
const path = require("path");
module.exports = {
stories: ["../**/stories.tsx"],
webpackFinal: (config) => {
return {
...config,
resolve: {
alias: {
api: path.resolve(__dirname, "src/api/"),
assets: path.resolve(__dirname, "src/assets/"),
components: path.resolve(__dirname, "src/components/"),
containers: path.resolve(__dirname, "src/containers/"),
i18n: path.resolve(__dirname, "src/i18n/"),
models: path.resolve(__dirname, "src/models/"),
pages: path.resolve(__dirname, "src/pages/"),
src: path.resolve(__dirname, "src/"),
stores: path.resolve(__dirname, "src/stores/"),
utils: path.resolve(__dirname, "src/utils/"),
},
},
module: {
...config.module,
rules: [
{
test: /\.(ts|js)x?$/,
exclude: /node_modules/,
use: { loader: "babel-loader" },
},
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
{ test: /\.(png|jpg|gif)$/, use: ["file-loader"] },
{
test: /\.svg$/,
use: [
{
loader: "babel-loader",
},
{
loader: "react-svg-loader",
options: {
jsx: true,
},
},
],
},
],
},
};
},
typescript: {
check: false,
checkOptions: {},
reactDocgen: "react-docgen-typescript",
reactDocgenTypescriptOptions: {
shouldExtractLiteralValuesFromEnum: true,
propFilter: (prop) =>
prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,
},
},
};
My app structure looks like this:
client
storybook
main.js
preview.js
src
components
pages
webpack.config.js
How to fix this?
I'm trying to load the 3D model with the .gltf extension in React with Typescript. The files in folder with 3D model are .gltf, .png and .bin files. The tools used for this task are webpack and useGLTFLoader from drei library. I've tried different tools. Mainly from three.js library with no effect. Error is showing that the 3D model is not found 404 (shown below) and nothing appears in place where 3D model should be placed.
GET http://localhost:3000/assets/models/Duck/glTF/Duck.gltf 404 (Not Found)
My component for rendering the 3D model is shown below:
import React, { Suspense } from 'react';
import { Canvas } from 'react-three-fiber';
import { useGLTFLoader } from 'drei';
const DuckModel = () => {
const gltf = useGLTFLoader('../../assets/models/Duck/glTF/Duck.gltf', true);
return <primitive object={gltf.scene} dispose={null} />;
};
export const ThreeDimensionComponent = () => {
return (
<>
<Canvas camera={{ position: [0, 0, 10], fov: 70 }}>
<Suspense fallback={null}>
<mesh position={[0, 250, 0]}>
<DuckModel />
</mesh>
</Suspense>
</Canvas>
</>
);
};
And below I share my webpack config.
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const root = __dirname;
const gsapPath = '/node_modules/gsap/src/uncompressed/';
module.exports = {
devtool: 'source-map',
mode: 'development',
entry: path.join(__dirname, 'src', 'index.tsx'),
watch: true,
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
sourceMapFilename: '[name].js.map'
},
module: {
rules: [
{
test: /\.(tsx|ts)$/,
use: ['babel-loader', 'ts-loader', 'tslint-loader']
},
{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')()],
sourceMap: true
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /\.(png|jp(e*)g|svg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8000,
sourceMap: true
}
}
]
},
{
test: /\.(ttf|eot|woff|woff2)$/,
use: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]',
sourceMap: true
}
}
},
{
test: /\.(glb|gltf)$/,
use: [
{
loader: 'file-loader'
// options: {
// outputPath: 'assets/models'
// }
}
]
},
{
test: /\.(bin)$/,
use: [
{
loader: 'file-loader'
}
]
}
]
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
modules: ['node_modules', path.resolve(__dirname, 'src')],
alias: {
TweenLite: 'gsap',
CSSPlugin: 'gsap',
Draggable: path.join(root, gsapPath + 'utils/Draggable.js'),
ScrollToPlugin: path.join(root, gsapPath + 'plugins/ScrollToPlugin.js')
}
},
devServer: {
historyApiFallback: true,
contentBase: './dist',
inline: true,
host: 'localhost',
port: 3000
},
plugins: [
new CleanWebpackPlugin({ verbose: true }),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src', 'index.html')
}),
new webpack.ProvidePlugin({
TweenMax: 'gsap'
}),
new CopyWebpackPlugin({
patterns: [{ from: 'src/assets' }]
})
]
};
My webpack.config.js file is in the root directory for the project. The assets folder is in the src folder. Lastly the file with React code is in src/components/ThreeDimensionComponent/ThreeDimensionComponent.tsx (so path for it is correct).
You either need to import the model and use the url you get from that (url-loader), or put it into the public folder. Your path points nowhere in the bundled output.
One more thing, it's #react-three/drei and useGLTF(url).
Here is a working example with a loaded 3D model in case anyone needed it. I marked an answer from hpalu as correct because it helped me to solve this problem.
I needed to use Suspense with a fallback that isn't an HTML element but instead is a component from react-three-fiber.
The post that also has helped me to solve the bug:
https://spectrum.chat/react-three-fiber/general/hello-im-trying-to-use-the-texture-loader-with-suspense~a9671405-3b8a-4486-a319-cad820347ddc?m=MTU4NDExMzIyMTMwOA==
Here is React component:
import { useGLTF } from '#react-three/drei';
import React, { Suspense } from 'react';
import { Canvas } from 'react-three-fiber';
const DuckModel = () => {
const gltf = useGLTF('./models/Duck/glTF/Duck.gltf', true);
return <primitive object={gltf.scene} dispose={null} />;
};
export const ThreeDimensionComponent = () => {
return (
<>
<Canvas camera={{ position: [0, 0, 3], fov: 80 }}>
<ambientLight intensity={0.3} />
<Suspense
fallback={
<mesh>
<boxBufferGeometry args={[1, 1, 1]} />
<meshStandardMaterial />
</mesh>
}
>
<DuckModel />
</Suspense>
</Canvas>
</>
);
};
And here is the webpack config for this example:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const gsapPath = '/node_modules/gsap/src/uncompressed/';
module.exports = {
devtool: 'source-map',
mode: 'development',
entry: path.join(__dirname, 'src', 'index.tsx'),
watch: true,
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
sourceMapFilename: '[name].js.map',
publicPath: '/'
},
module: {
rules: [
{
test: /\.(tsx|ts)$/,
use: ['babel-loader', 'ts-loader', 'tslint-loader']
},
{
test: /\.scss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'postcss-loader',
options: {
plugins: [require('autoprefixer')()],
sourceMap: true
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /\.(png|jp(e*)g|svg|gif)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 8000,
sourceMap: true
}
}
]
},
{
test: /\.(ttf|eot|woff|woff2)$/,
use: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]'
// sourceMap: true
}
}
},
{
test: /\.(glb|gltf)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'assets/models',
sourceMap: true
}
}
]
},
{
test: /\.(bin)$/,
use: [
{
loader: 'file-loader',
options: {
outputPath: 'assets/models',
sourceMap: true
}
}
]
}
]
},
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.json'],
modules: ['node_modules', path.resolve(__dirname, 'src')],
alias: {
TweenLite: 'gsap',
CSSPlugin: 'gsap',
Draggable: path.join(__dirname, gsapPath + 'utils/Draggable.js'),
ScrollToPlugin: path.join(__dirname, gsapPath + 'plugins/ScrollToPlugin.js')
}
},
devServer: {
historyApiFallback: true,
contentBase: './dist',
inline: true,
host: 'localhost',
port: 3000
},
plugins: [
new CleanWebpackPlugin({ verbose: true }),
new HtmlWebpackPlugin({
template: path.join(__dirname, 'src', 'index.html')
}),
new webpack.ProvidePlugin({
TweenMax: 'gsap'
}),
new CopyWebpackPlugin({
patterns: [{ from: 'src/assets' }]
})
]
};
Can someone help me with the Issue in my React Website?
We have used react-loadable for chunks whenever we deploy it on production environment the website get stuck on the loading part. Below is the URL
URL WITH LOADABLE: http://fcastage.surge.sh/
Any help will be appreciated.
We have tried making the website using react loadabale and without react loadable. But to make the website fast and load in chunks we have to use loadable . The react loadable is working fine with Development Environment but its not working when I am switching to Production.
Below is the Config File for Production
const HtmlWebpackPlugin = require("html-webpack-plugin");
//const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const path = require("path")
const webpack = require('webpack');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { ReactLoadablePlugin } = require('react-loadable/webpack')
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
mode: "production",
entry: "./app/index.js",
output: {
path: path.resolve(__dirname, "./build"),
filename: '[name].bundle.js',
chunkFilename: '[name].js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract("style-loader", "css-loader")
},
{
test: /\.less$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: [
{
//because remove style-loader,my css can't work
loader: "css-loader",
options: {
importLoaders: 1,
modules: true,
localIdentName: "[local]"
} // translates CSS into CommonJS
},
{
loader: "less-loader" // compiles Sass to CSS
}
]
})
},
{
test: /\.(jpe?g|png|gif|svg|ico)$/i,
use: [
{
loader: "url-loader",
options: {
outputPath: "assets/",
limit: 10 * 1024
}
}
]
},
{
test: /\.(woff|woff2|eot|ttf)$/i,
use: [
{
loader: "url-loader",
options: {
outputPath: "assets/"
}
}
]
}
]
},
optimization : {
splitChunks: {
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
}
}
}
// minimizer: [
// new UglifyJsPlugin({
// uglifyOptions: {
// compress: {
// unused: true,
// dead_code: true,
// warnings: false
// }
// },
// sourceMap: true
// }),
// ]
},
plugins: [
new HtmlWebpackPlugin({
template: "./app/index.html",
hash: true,
filename: "index.html"
}),
//for surge.sh
new HtmlWebpackPlugin({
template: "./app/index.html",
hash: true,
filename: "200.html"
}),
new CleanWebpackPlugin(),
new ExtractTextPlugin("main.css"),
new webpack.DefinePlugin( {'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.DEBUG': JSON.stringify(process.env.DEBUG) } ),
new ReactLoadablePlugin({
filename: path.resolve(__dirname, "build/react-loadable.json")
})
],
};
I'm trying to integrate the monaco editor into an existing react application. I followed the installation steps from (react-monaco-editor), but I don't get any syntax highlighting or autocomplete for typescript, consistent with the FAQ as if I hadn't set up the monaco-editor-webpack-plugin.
I have setup the plugin though. I can see that the monaco-editor-webpack-plugin is dropping files along side my app.js, so I presume it is working:
It seems my issue is that react-monaco-editor is trying to pull these files from the wrong location. If I load my page and open my network tab, I can see the following:
There are two problems:
1 - the paths are full paths on my system but should be relative paths - e.g.
http://127.0.0.1/dist/app/secured/49.js
2 - there is a slash missing between "secured" and "49.js" (secured49.js) and also for the other numeric files, but the editor.worker.js has the slash (weird).
So the question I'm hoping to answer is - how does react-monaco-editor determine the paths it will pull these files from, and is there a way I can influence the pathing?
Any help or recommendations would be much appreciated! Some snippets of my code below in case helpful.
package.json:
"monaco-editor-webpack-plugin": "^1.7.0",
"react-monaco-editor": "^0.26.2",
weback.config.js
'use strict';
const path = require('path');
const webpack = require('webpack');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const MonacoWebpackPlugin = require('monaco-editor-webpack-plugin');
process.noDeprecation = true;
const babel = {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: [
['#babel/plugin-proposal-decorators', { 'legacy': true }],
['jsx-control-statements'],
'#babel/plugin-proposal-function-bind',
['#babel/plugin-proposal-decorators', { 'legacy': true }],
['#babel/plugin-proposal-class-properties', { 'loose': true }]
],
compact: true
}
};
const config = {
entry: './index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js'
},
mode: 'development', // Change to production on checkin
context: settings.app(),
resolve: {
modules: [
settings.app(),
path.join(settings.project(), 'node_modules'),
path.join(__dirname, 'node_modules')
],
symlinks: true,
extensions: ['.js', '.jsx', '.json', '.css', 'scss', 'less']
},
resolveLoader: {
modules: [
path.join(settings.project(), 'node_modules'),
path.join(__dirname, 'node_modules')
],
symlinks: true
},
module: {
rules: [
{
test: /.(js|jsx)?$/,
use: [
{
loader: 'babel-loader',
options: {
presets: [
'#babel/preset-env',
'#babel/preset-react'
],
plugins: [
'#babel/plugin-proposal-function-bind',
['jsx-control-statements'],
['#babel/plugin-proposal-decorators', {'legacy': true}],
['#babel/plugin-proposal-class-properties', { 'loose': true }]
],
compact: true
}
}
],
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif)$/i,
use: [
{
loader: 'url-loader',
options: {
limit: 8192
}
}
]
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.less$/,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'less-loader'
}
]
},
{
test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 100000,
mimetype: 'application/font-woff'
}
}]
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 100000,
mimetype: 'application/octet-stream'
}
}]
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
use: [{
loader: 'url-loader',
options: {
limit: 100000,
mimetype: 'application/image/svg+xml'
}
}]
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
use: 'file-loader'
},
{
test: /-font\.otf(\?.+)?$/,
use: [
'file-loader?name=fonts/[name].[ext]'
]
}
]
},
devtool: 'source-map',
node: {
console: true,
fs: 'empty',
net: 'empty',
tls: 'empty'
},
plugins: [
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
new CaseSensitivePathsPlugin(),
new MonacoWebpackPlugin()
]
};
module.exports = config;
index.js
import { observer } from 'mobx-react';
import React, { Component } from 'react';
import MonacoEditor from 'react-monaco-editor';
#observer
export default class TSEditor extends Component {
constructor(props) {
super(props);
this.state = {
code: 'var name : string = "kyle";'
};
this.editorDidMount = this.editorDidMount.bind(this);
this.onChange = this.onChange.bind(this);
}
onChange(newValue, e) {
console.log('onChange', newValue, e);
}
editorDidMount(editor, monaco) {
console.log('editorDidMount', editor);
editor.focus();
}
render() {
const code = this.state.code;
const options = {
selectOnLineNumbers: true
};
return (
<MonacoEditor
language="typescript"
theme="vs-dark"
value={code}
options={options}
onChange={this.onChange}
editorDidMount={this.editorDidMount}
/>
);
}
}
I my case... this did the trick... within webpack.config.js
devServer: {
https: true,
port: 3000,
publicPath: "/dist/"
},
...
..
.
plugins: [
...
..
.
new MonacoWebpackPlugin({
publicPath: "/dist/"
})
]
available options are documented at https://github.com/Microsoft/monaco-editor-webpack-plugin#options
This turned out to be a problem caused by an incorrect publicPath in the output portion of my webpack configuration.
For anyone else with a similar issue, add a publicPath in your webpack configuration that gives the correct location of your web worker JS files.
Im trying to get my images to appear in my build version of my react code.
```import reportIcon from "../../../../../src/img/reportmanager.svg";
<img src={reportIcon } className="img-icons-list" />```
this code works when I am in build version. My reportmanager icon shows up, but when I navigate to www.mywebsite.com/reports/user -- the icon disappears
import reportIcon from "/src/img/reportmanager.svg";
does not work either. here is my webpack.config.js file
```const HtmlWebPackPlugin = require("html-webpack-plugin");
const ExtractTextPlugin = require("extract-text-webpack-plugin");
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname + '/public'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env',
'#babel/react', {
'plugins': ['#babel/plugin-proposal-class-properties']
}]
},
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(eot|ttf|woff|woff2)$/,
loader: 'file-loader?name=./font/[name]_[hash:7].[ext]'
},
{
test: /\.(jpg|png|svg)$/,
loader: 'file-loader?name=./img/[name]_[hash:7].[ext]'
}
]
},
devServer: {
historyApiFallback: {
index: "/",
}
},
plugins: [
new ExtractTextPlugin("css/style.css"),
new HtmlWebPackPlugin({
template: "./src/index.html",
filename: "./index.html"
}),
function () {
this.plugin("done", function (stats) {
if (stats.compilation.errors && stats.compilation.errors.length && process.argv.indexOf('--watch') == -1) {
console.log(stats.compilation.errors);
process.exit(1); // or throw new Error('webpack build failed.');
}
// ...
});
}
]
};
I needed to put
<base href="/">
in the index.html of my react project.