I added react-svg-loader and tried to import an svg per the documentation, yet I keep running into "Can't find the module.."
import * as React from 'react';
import FlickrLoader from './FlickrLoader.svg';
// tslint:disable-next-line:variable-name
const Loader = props => (
<FlickrLoader className="center" />
);
export default Loader;
In the root folder, I have custom.d.ts which as declare module '*.svg';
Can anyone think of something that I may be missing as to why TypeScript won't pick up the .svg file in the same directory?
Related
I hope someone can tell me where I am going wrong in trying to get usable libraries
I have created a NPM project using create-react-app --format typescript, I then created the following structure:
|->tsconfig.json
|->package.json
|->config
|->tsconfig.base.json
|->tsconfig.cjs.json
|->tsconfig.esm.json
|->src
|->index.tsx
|->components
|->index.ts
|->ExampleComponent
|->ExampleComponent.component.tsx
|->ExampleComponent.stories.tsx
|->ExampleComponent.types.ts
|->index.ts
In this example the Example Component looks something like the following:
|->tscon
import React, { FC } from 'react';
// Contact specific icons
import Container from 'react-bootstrap/Container';
// Footer Properties
import { ExampleProperties } from './ExampleComponent.types';
export const ExampleComponent: FC<ExampleProperties> = ({ text }) => {
return (<Container fluid>{text}</Container>);
};
for the tsconfig files in 'config' I've lifted the Synk recommendation directly, while tsconfig.json is fairly simple like so:
{
"extends": "./configs/tsconfig.esm.json",
}
If I start the application via 'npm start' I get a website and the component correctly appears, but the issue is trying to import into another project.
I using npm link and npm link #Example/ExampleProject to bring the project in to another website and the index.tsx of that project looks like so:
import React from 'react';
import { createRoot } from 'react-dom/client';
import { ExampleComponent } from '#Example/ExampleProject';
const container = document.getElementById('root');
if (!container) throw new Error('Failed to find the root element') const root = createRoot(container);
root.render(
<React.StrictMode>
<main role={"main"} >
<ExampleComponent/>
</main>
</React.StrictMode> );
But when it starts I am getting this error:
Module not found: Error: Can't resolve './ExampleComponent/index' in '/home/user/IdeaProjects/ExampleProject/dist/esm' Did you mean 'index.mjs'? BREAKING CHANGE: The request './Common/index' failed to resolve only because it was resolved as fully specified (probably because the origin is strict EcmaScript Module, e. g. a module with javascript mimetype, a '*.mjs' file, or a '*.js' file where the package.json contains '"type": "module"'). The extension in the request is mandatory for it to be fully specified. Add the extension to the request.
The only thing I can think is tsc generates src/components/index.ts as a /src/component/index.js (which I rename). But ExampleComponent has .js and .mjs files within its directory
Let's say I have two React components:
import { React } from "react";
import "./styles.css";
function ComponentA() {
...
}
export default ComponentA;
import { React } from "react";
import "./styles.css";
function ComponentB() {
...
}
export default ComponentB;
Both of these components are importing the same CSS file styles.css. Now let's say that in my app, I'm importing both of these components, so App.js looks something like this:
import { ComponentA } from "./ComponentA";
import { ComponentB } from "./ComponentB";
function App() {
return (
<div className="App">
<ComponentA />
<ComponentB />
</div>
);
}
export default App;
What exactly happens here? Does my app import the same CSS file twice? And if so, do I just make the import on the App.js file instead?
It's as if it was only imported once.
When a module bundler like Webpack sees an import, it puts the following path in the list of files to process, if the path doesn't exist already. The file is only processed once, no matter how many times it's imported.
Note that with React apps, you will often see
import React from "react";
in tens or hundreds of files - React isn't created anew hundreds of times. Rather, the module is processed once, and then files that import it are given access to what React has exported.
Importing CSS files works the same way, in that they're only processed once no matter how many times an import exists for them (though they don't really have exports, just side-effects).
If both ComponentA and ComponentB depend on styles.css, feel free to keep importing styles.css in both - it doesn't hurt, and will make things easier to manage when you can see at a glance that both components directly depend on that CSS.
I have a React app that imports components from an own library of components. The library of components is a .js bundle created with Webpack.
The component that I am importing, imports another file which imports SVG files.
Original non-bundled file which imports SVGs:
import React from "react";
import {ShoppingBag32} from '#carbon/icons-react';
import {ReactComponent as OwnIcon} from "../design/icons/OwnIcon.svg";
const foo = {
shop: <ShoppingBag32/>,
ownIcon: <OwnIcon/>,
};
export default foo;
The #carbon/icons-react icons which are precompiled in their own plain JS bundle, work fine. But my own SVG fails to work.
I get:
Warning: React.createElement: type is invalid -- expected a string (for built-in components) or a
class/function (for composite components) but got: undefined. You likely forgot to export your component
from the file it's defined in, or you might have mixed up default and named imports.
The stack trace of the warning leads to the line in the bundle where ownIcon is defined. You can see that the working icon of the 3rdparty bundle points to a ShoppingBag32 key, and my own SVG points to a ReactComponent key.
var foo = {
shop: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(_carbon_icons_react__WEBPACK_IMPORTED_MODULE_0__["ShoppingBag32"], null),
ownIcon: /*#__PURE__*/react__WEBPACK_IMPORTED_MODULE_2___default.a.createElement(_design_icons_SolarPanel32_svg__WEBPACK_IMPORTED_MODULE_1__["ReactComponent"], null)
};
Any ideas on how fix the SVG import?
EDIT
I found out a workaround, the img tag can be used with the SVG path as source. But I don't like this solution because I would like the entire SVG markup to be rendered in the DOM instead of an img tag.
import React from "react";
import {ShoppingBag32} from '#carbon/icons-react';
import OwnIcon from "../design/icons/OwnIcon.svg";
const foo = {
shop: <ShoppingBag32/>,
ownIcon: <img src={OwnIcon}/>,
};
export default foo;
If you are using the default create react app, you will need to reference your SVG as follows:
import OwnIcon from "../design/icons/OwnIcon.svg";
The reason it is like import {ShoppingBag32} from '#carbon/icons-react'; for carbon is because it is referenced as an export in that package as opposed to locally which webpack needs a name for the default export of an image.
Ok I've looked everywhere and there is no documentation on this Babel module
--babel-plugin-named-asset-import
can someone please explain what it is for and how it works.
Looks like its purpose is to import named exports from non JS/CSS assets. Currently, within the CRA, it appears to only be implemented for svg assets. The goal is to offer another way to import SVGs as React components versus the standard import as a url that needs to be applied to an img element.
Without plugin (default import)
import * as React from 'react';
import logo from './logo.png'; // import file as a url
function Header() {
return <img src={logo} alt="logo" />;
}
export default Header;
With plugin (named import)
import * as React from 'react';
import { ReactComponent as Logo } from './logo.svg'; // import file as a React component
function Header() {
return <Logo />;
}
export default Header;
Update
Going deeper, it appears that the plugin aids in importing svg files in the following ways:
import logo from "logo.svg"; // default import
import { logoUrl } from "logo.svg"; // named import
import { ReactComponent as Logo } from "#svgr/webpack?-svgo!logo.svg"; // ReactComponent import
The CRA specifically targets svg file formats as shown in their test suites. As to whether or not it supports other non-js files, not likely (especially since the babel plugin is only utilized once in the CRA webpack config).
As mentioned in the svgr docs:
SVGR can be used as a webpack loader, this way you can import your SVG directly as a React Component.
This particular plugin aims to import any svg file as the default export.
Please note that by default, #svgr/webpack will try to export the React Component via default export if there is no other loader handling svg files with default export.
Whereas the CRA appears to utilize file/url loader for the default/named exports and specifically maps a ReactComponent named export to the svgr webpack plugin.
I'm trying to load in an image file that's contained within my src folder. I'm loading it into App.js like so:
import React, { Component } from 'react';
import './App.css';
import logo from 'images/logo.png';
class App extends Component {
render() {
return (
<header>
<img src={logo} alt={"logo"}/>
</header>
);
}
}
export default App;
Unfortunately, I get this error:
./src/App.js
Module not found: Can't resolve 'logo.png' in '/src'
I arrived at this code with this Stack Overflow answer: https://stackoverflow.com/a/35454832/7386637
..but what am I doing wrong here?
If you want to be using file paths like this, you need to add a resolve property to your webpack config, like so
resolve: {
modules: [path.resolve(__dirname, 'PATH_THAT_HOLDS_YOUR_IMAGE_DIRECTORY')]
},
So for example if your images live in project/assets/images/ and your webpack config lives in project/ then in the above you would replace PATH_THAT_HOLDS_YOUR_IMAGE_DIRECTORY with assets.
Using import logo from 'images/logo.png'; would work then. (Reminder that you need to restart your dev-server in order for changes in webpack config to take effect)
Otherwise, relative paths will work fine, as mentioned.