how to load Svg components in remix run application - reactjs

I have some Svg files which i want to load as react components in remix run app.
for example in create-react-app your could do something like this
import { ReactComponent as Logo } from './logo.svg';
function App() {
return (
<div>
{/* Logo is an actual React component */}
<Logo />
</div>
);
}
is there any similar way in remix-run do achieve the same ?

I created a workflow to convert the icons to react components in development using svgr and npm-watch. For good measure you will probably want to run the icons script before building for production too.
Install dependencies:
npm install -D #svgr/cli #svgr/plugin-svgo #svgr/plugin-jsx #svgr/plugin-prettier npm-watch npm-run-all
Update package.json scripts:
{
//...
"scripts": {
//...
// task to convert icons to components
"icons": "npx #svgr/cli --out-dir app/icons -- ./icons",
// watch task
"icons:watch": "npm-watch icons",
// compile once and start watching for changes
"dev:svg": "run-s icons icons:watch",
// remix dev
"dev:remix": "remix dev",
// run all dev: scripts including `dev:svg` (depending on the remix template you might need to replace the default `dev` script)
"dev": "run-p dev:*"
},
// npm-watch configuration
"watch": {
"icons": {
"patterns": [
"icons"
],
"extensions": "svg",
"quiet": false
}
},
//...
}
The svg icon files are located in the project root in icons/ and the react components are generated in the app/icons/ folder.
svgr.config.js (optional)
module.exports = {
plugins: ["#svgr/plugin-svgo", "#svgr/plugin-jsx", "#svgr/plugin-prettier"],
typescript: true, // optional
};
svgo.config.js
module.exports = {
plugins: [
{
name: "preset-default",
params: {
overrides: {
removeViewBox: false,
},
},
},
],
};

Unfortunately there is no way currently to import an SVG file in your component file directly like in create react app.
And maintainers do not allow currently manipulating the esbuild config to add features like that via plugins (cf. the discussion in this merge request).
If you don't need to style your SVG, you could simply put it in the public/ folder and include it with an img element in your component.
Smaller JS bundles, faster page hydration, and immutable .svg's over the network that are only ever downloaded once. (cf. this message)
function App() {
return (
<div>
<img src="/logo.svg" alt="My logo" />
</div>
);
}
You could also create yourself a JSX component and put your SVG code inside it (with some manual conversion for prop names), or even put your SVG file in a folder, and use an external automatic conversion tool like SVGR to generate optimized JSX component from it with a simple CLI command.
In that case you have a component that you can import like any other component:
import Logo from './Logo.svg';
function App() {
return (
<div>
<Logo />
</div>
);
}

For me, it only worked by creating a component with the SVG tag and then importing it
const HomeLogo = () => {
return (
<div>
<svg xmlns="http://www.w3.org/2000/svg" width="48" height="48">
<g fill="none" fill-rule="evenodd">
<circle cx="24" cy="24" r="24" fill="#FFF"/>
<path fill="#0B0D17" d="M24 0c0 16-8 24-24 24 15.718.114 23.718 8.114 24 24 0-16 8-24 24-24-16 0-24-8-24-24z"/>
</g>
</svg>
</div>
)
}
export default HomeLogo

You can just import them as described in the documentation:
import type { LinksFunction } from "#remix-run/node"; // or "#remix-run/cloudflare"
import styles from "./styles/app.css";
import banner from "./images/banner.jpg";
export const links: LinksFunction = () => {
return [{ rel: "stylesheet", href: styles }];
};
export default function Page() {
return (
<div>
<h1>Some Page</h1>
<img src={banner} />
</div>
);
}

Related

Issue with rendering images on Gatsby site deployed to github pages [duplicate]

I am having trouble getting images to display on github pages. I am using a repository based page. I have added in a simple img tag with in the JSX and tried using the method described in the Gatsby documentation. I feel like I'm missing something obvious.
Here is the code
import React, { useContext } from 'react';
import AnchorLink from 'react-anchor-link-smooth-scroll';
import { ThemeContext } from 'providers/ThemeProvider';
import { Header } from 'components/theme';
import { Container, Button } from 'components/common';
import dev from 'assets/illustrations/dev.svg';
import { Wrapper, IntroWrapper, Details, Thumbnail } from './styles';
import { withPrefix } from 'gatsby'
import HeadShotPlaceHolder from 'assets/images/HeadShotPlaceHolder.jpeg'
export const Intro = () => {
const { theme } = useContext(ThemeContext);
console.log(HeadShotPlaceHolder)
return (
<Wrapper>
<Header />
<IntroWrapper as={Container}>
<Details theme={theme}>
{/* <h1>Hi There!</h1> */}
<h1>Pamela Welch</h1>
{/* <h4>I’m John and I’m a JAMStack engineer!</h4> */}
<h4>A proven professional with extensive experience in all facets of communication and marketing.</h4>
<Button as={AnchorLink} href="#contact">
Hire me
</Button>
</Details>
<Thumbnail>
{/* This is where the image tag giving me the problem is */}
<img src={ withPrefix(HeadShotPlaceHolder) } alt="I’m John and I’m a JAMStack engineer!" />
</Thumbnail>
</IntroWrapper>
</Wrapper>
);
};
and here is the result
Image Link Broken
Your code looks good, your image has its path prefixed. However, to make it effective you need to run the following snippet in the deploy command:
{
"scripts": {
"deploy": "gatsby build --prefix-paths && gh-pages -d public"
}
}
Note the --prefix-paths flag.
More information in How Gatsby Works in GitHub Pages.

next-dev.js:89 TypeError: Cannot read property 'parentNode' of null

I am getting this error after building via npm run build and starting the it with npm run start
any idea why this error is showing ?
My whole layout is also wrong, I am guessing because of the tailwindcss error
this is my _app.tsx
import type { AppProps } from 'next/app'
import "tailwindcss/tailwind.css"
import "../styles/styles.scss"
import { Provider, useSelector } from 'react-redux'
import { Application } from 'react-rainbow-components'
import { ThemeStore } from '../config/redux/ThemeStore'
import { theme } from '../config/react-rainbow/react-rainbow-config'
import { ThemeState } from '../config/redux/ThemeReducer'
import Navigation from '../components/navigation/Navigation'
const Child: React.FC = ({ children }) => {
const isDark = useSelector<ThemeState, ThemeState["isDark"]>(state => state.isDark)
return <div className={`${isDark ? "dark blackThemeColor test" : "white whiteThemeColor"}` + " min-h-screen font-body pr-0"} style={{ height: '150vh' }}>{children}</div>;
}
const MyApp = ({ Component, pageProps }: AppProps) => {
return (
<Provider store={ThemeStore}>
<Application theme={theme}>
<Child>
<Navigation />
<Component {...pageProps} />
</Child>
</Application>
</Provider>
);
};
export default MyApp
All help is appreciated
#juliomalves pointed out that I was importing tailwindcss/tailwind.css while it wasn't needed.
This was because when setting the project up I read this in the docs
Import Tailwind directly in your JS If you aren't planning to write
any custom CSS in your project, the fastest way to include Tailwind is
to import it directly in pages/_app.js:
After relooking there was also this option
Include Tailwind in your CSS Open the ./styles/globals.css file that
Next.js generates for you by default and use the #tailwind directive
to include Tailwind's base, components, and utilities styles,
replacing the original file contents:
So I removed the tailwindcss import and imported in my scss file the tailwind like this:
#tailwind base;
#tailwind components;
#tailwind utilities;
Now when npm run build and npm run start the layout is correct and the error is gone

How to call image into reactjs and airtable

Am using airtable.com helloworld sample code. my logo.jpg is in the same directory as the index.js files
myproject-folder\frontend\index.js
myproject-folder\frontend\logo.png
The airtable app is not using webpack so I could not import the logo image.
I have tried calling the image directly as per code
below but could not get it to work.
<img src={window.location.origin + './logo.jpg'} />
<img src={'./logo.jpg'} />
here is the code
import {
initializeBlock,
useBase,
useRecords,
} from '#airtable/blocks/ui';
import React, { Component } from "react";
class App extends Component {
render() {
return (
<div>
<h2>Hello world from Airtable</h2>
<img src={'./logo.jpg'} />
</p>
</div>
);
}
}
export default App;
If I understand correctly you are using webpack to build your app.
Webpack treat assets as dependencies. As such, you need to import your image and use an appropriate loader to handle the file type of your logo.
From webpack's documentation:
[...] When you import MyImage from './my-image.png', that image will
be processed and added to your output directory and the MyImage
variable will contain the final url of that image after processing.
[...] The loader will recognize this is a local file, and replace the
'./my-image.png' path with the final path to the image in your output
directory.
In your case, you could do this:
import React, { Component } from "react";
import {
initializeBlock,
useBase,
useRecords,
} from '#airtable/blocks/ui';
import logo from './logo.png';
class App extends Component {
render() {
return (
<div>
<h2>Hello world from Airtable</h2>
<img src={logo} />
</div>
);
}
}
export default App;
You'd then need to add the file-loader to your webpack config file:
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader',
],
},

Only load Snipcart on specific page in Gatsby

I'm using Snipcart Plugin in Gatsby but the script gets loaded everywhere. Is is it possible with some sort of function to trigger the script on only 1 specific page and not entirely?
Below are the options I'm using in my Gatsby-config.js file
{
resolve: "gatsby-plugin-snipcart",
options: {
apiKey: process.env.SNIPCART_API,
autopop: true,
js: "https://cdn.snipcart.com/themes/v3.0.8/default/snipcart.js",
styles: "https://cdn.snipcart.com/themes/v3.0.8/default/snipcart.css",
jquery: false,
},
},
You should take a look at gatsby-plugin-snipcartv3. I believe the gatsby-plugin-snipcart is deprecated and is not working with Snipcart v3.
But as far as I know, there's no way to tell the plugin to load the script only on specific pages.
You could use Snipcart directly, not using the plugin, to have more control over it.
Let's say you have a layout.js file, wrapping content for your page, you can have a loadSnipcart flag that will load Snipcart files only when you need them.
Here's an example:
layout.js
import React from "react"
import Helmet from "react-helmet"
export default ({ loadSnipcart, children }) => {
const Snipcart = () => {
if (!loadSnipcart) return null
return (
<Helmet>
<script
src="https://cdn.snipcart.com/themes/v3.0.8/default/snipcart.js"
type="text/javascript"
/>
<link
href="https://cdn.snipcart.com/themes/v3.0.8/default/snipcart.css"
rel="stylesheet"
/>
</Helmet>
)
}
return (
<div id="main-content">
<Snipcart />
{children}
</div>
)
}
shop.js
import React from "react"
import Layout from "./layout"
export default () => {
return (
<Layout loadSnipcart>
<h1>Welcome to my shop !</h1>
</Layout>
)
}
index.js
import React from "react"
import Layout from "./layout"
export default () => {
return (
<Layout>
<h1>This page doesn't load Snipcart</h1>
</Layout>
)
}

Not able to import SVG image into my typescript application

I am trying to import an image (SVG) into my typescript application
import * as logo from './images/logo';
export default class App extends React.Component<{}, {}>{
render() {
return (
<div className="App">
<header className="App-Header">
<img src={logo} className="App-logo" alt="logo" />
<h1 className="App-tite">Welcome to React</h1>
</header>
</div>
);
}
}
but typescript still throws the error
ERROR in [at-loader] ./src/App.tsx:3:24
TS2307: Cannot find module './images/logo'.
I have a directory called images in the same location as App.tsx and it does have a logo.svg. In my webpack.config.js I also have a entry
resolve: {
extensions: [".js", ".tsx", ".css", ".svg"]
}
I googled and found this thread https://github.com/microsoft/TypeScript-React-Starter/issues/12
But I don't know where to put globals.d.ts file (as recommended in the last post)
Also why is importing a simple image so hard?
Here is my repo
https://github.com/abhsrivastava/redux-tutorial
One way of easily importing inline SVG files would be to make use of this package called svg-inline-react, which wraps your SVG into a component.
You can try installing it
npm i svg-inline-react
And on your component,
import InlineSVG from 'svg-inline-react';
import logo from './images/logo.svg';
export default class App extends React.Component<{}, {}>{
render() {
return (
<div className="App">
<header className="App-Header">
<div className="App-logo" />
<InlineSVG src={logo} />
</div>
<h1 className="App-tite">Welcome to React</h1>
</header>
</div>
);
}
}
In addition, you might need to configure your webpack.config by adding an additional rule.
module.exports = {
//...
module: {
rules: [
//...
{
test: /\.svg$/,use: 'svg-inline-loader'
}
]
}
};
And then, you might need to declare the typings too.
interface SvgInlineReactProps {
src: string;
raw?: boolean;
element?: string;
}
declare module 'svg-inline-react' {
export default class InlineSVG extends React.Component<SvgInlineReactProps, any> {
}
}
There is a couple of things, one of them is that your import is missing the extension, and by default it will try to look for a .ts file. Since you are importing the svg, you should do something like
import Logo from './images/logo.svg';
The other thing is, like you mentioned it yourself, you are missing a definitions file for that logo. You can either, next to logo.svg, create a logo.svg.d.ts or somewhere in your application create the globals.d.ts (it can be any name, any location)
Keep in mind that if you declare the module wrong, it will still not find it
The safest way is declare module '*.svg'; inside the global definitions file
If you are writing a typescript application, I suggest you use the microbundle package bundler make configurations easier. Microbundle is a “zero-configuration bundler for tiny modules".It’s a wrapper around rollup with sane defaults nice outputted size stats, multiple target formats (ES modules, CommonJS, UMD).
If you want to take a look https://github.com/developit/microbundle
--external flag to specify external dependencies
package.json
{
"name": "",
"author": ",
"version": "1.0.0",
"description": "",
"source": "src/index.tsx",
"main": "dist/index.js",
"exports": "./dist/index.modern.js",
"unpkg": "dist/index.umd.js",
"scripts": {
"dev": "microbundle watch --external .*/font/.*,.*/style/.*",
"build": "microbundle"
},
"devDependencies": {
"microbundle": "^0.13.0"
},
"keywords": [],
"license": "ISC"
}

Resources