Background:
I am building a reusable carousel component using react-multi-carousel library which requires a direct css import into my React component so the carousel component can render specific styles, ie import 'react-multi-carousel/lib/styles.css';. I am currently using tsc to bundle/compile my ts code, but when looking at the bundle, the css import/styles doesn't get resolved. Below is the compiled code (just the imports) in which you can see the css import is imported like so:
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
import { useRef } from 'react';
import ScrollingCarousel from 'react-multi-carousel';
import 'react-multi-carousel/lib/styles.css';
import styled from 'styled-components';
The issue I have is this forces the consuming app of this reusable component to have to use specific compiler to know how to handle css imports into a jsx file (such as css-loader and style-loader for webpack). Is there a way that I can compile this CSS file down to styles within the js file rather than an import so I can avoid css compiling in the consuming app?
Thanks in advance
Related
I have monorepo with a UI library inside packages which contains a lot of components. Every component also has a *.stories.tsx file. Under the apps folder is the storybook project, which loads the stories from #my-ui-library.
I have a decorator in the storybook config, so my ThemeContextProvider is wrapped around everything (ThemeContextProvider is also imported from #my-ui-library).
Does not work:
button.tsx
import { ThemeContext } from '../../ThemeContext'
Does work:
button.tsx
import { ThemeContext } from '#my-ui-library'
Using the relative import I get the error that theme, which is stored in ThemeContext, is undefined.
Now, that itself wouldn't be a problem if VS Code wouldn't auto import from the relative path and I didn't have to change it manually everywhere.
There a UMD bundle with React application that is hosted on CDN and is loaded dynamically when needed. React and ReactDOM are not bundled and it's expected that environment will have them available. The whole application is built using Webpack. I have the following code with SystemJS#0.21 that works:
import React from 'react';
import ReactDOM from 'react-dom';
import SystemJS from 'systemjs/dist/system-production'; // 0.21
SystemJS.registry.set('React', SystemJS.newModule(React));
SystemJS.registry.set('ReactDOM', SystemJS.newModule(ReactDOM));
const URL = 'https://example.com/bundle.js'; // UMD bundle
class App extends React.Component {
componentDidMount() {
SystemJS.import(URL).then(module => this.setState({ module }));
}
render() {
const Component = this.state.module?.default;
return Component ? <Component /> : null;
}
}
Is there a way to make it work with SystemJS#6.0, or load any other way? It works now but using old version sits uneasily with me. Changing format of downloaded package from UMD to SystemJS is next to impossible because there's a lot of consumers that I don't control.
I managed to get SystemJS 6.6.1 working in an Angular project in order to laod a UMD bundle.
You can find the details over here: https://stackoverflow.com/a/63917606/2528609.
The most important part, I think, is that you need to load an additional script to handle UMD modules => "node_modules/systemjs/dist/extras/amd.js"
I was wondering and trying to find out how webpack internally finds out which are the import statements a entry file has?
For example my index.js looks like
import React, { PropTypes, Component } from 'react';
import { findDOMNode } from 'react-dom';
import classnames from 'classnames';
import Loading from 'components/Loading';
import Button from 'components/Button';
import Header from 'components/Header';
import Footer from 'components/Footer';
class App extends Component {
render() {
return (
<div className="shopping-list">
<Header />
<h1>Shopping List for {this.props.name}</h1>
<ul>
<li>Instagram</li>
<li>WhatsApp</li>
<li>Oculus</li>
</ul>
<Footer />
</div>
);
}
};
export default App;
Now I am trying to understand how webpack is finding out what are the other imports that file has? And then one of the imported files has other imported files?
Basically, Webpack is build tool and it is design to convert your app into optimized solution like compressing the js/scss/css and many more files.
Webpack can be configurable according to your choice and there are many loaders and plugins developed, you can use them to add support for that type of file.
It's like telling a system to take list of source files (input) and compiling them by using related webpack plugin or loader and giving optimized solution as output.
by webpack configuration, you tell it that load this type of file and generate output here and it normally convert your advanced source code to native source code so, it can work on any system.
for example,
we know that scss file is not supported by browsers, we need to convert it into css and then we can import it, but using scss loader plugin and by configuring it with webpack you can directly use scss file no need to manually convert scss to css and directly can import scss file into component and webpack will read the file, see the type and convert it for us.
configuring the webpack is the difficult part but there are pretty good pre-configured solution available to use like create-react-app where you don't need to worry about the configurations
for more info see the webpack documentation
So my understanding is that when you are distributing a React component for others to use, you should ship the compiled version of it, rather than the source and expecting the end-user to deal with integrating it into their own build process.
That sounds reasonable, but I am not sure the best strategy for bundling css and other assets like images.
One way would be to inline, but inlining seems discouraged for anything of moderate size.
Another way could be to import the css and images into the file that is importing the component from the library. Then the build process of the end-user's app would handle the rest. Like:
import CoolComponent from 'CoolReactLibrary';
import 'CoolReactLibrary/css/styles.css';
import 'CoolReactLibrary/images/logo.png';
...
That seems cumbersome and even more so if I have a component library of a bunch of smaller components like this:
import PrimaryButton from 'CoolReactLibrary/buttons';
import 'CoolReactLibrary/buttons/primary-button/styles.css';
import Card from 'CoolReactLibrary/layout';
import 'CoolReactLibrary/layout/card/styles.css';
import VerticalMenu from 'CoolReactLibrary/menus';
import 'CoolReactLibrary/menus/vertical-navigation/styles.css';
My preference would be to just have the end-user do this:
import PrimaryButton from 'CoolReactLibrary/buttons';
import Card from 'CoolReactLibrary/layout';
import VerticalMenu from 'CoolReactLibrary/menus';
And everything from there just work.
Anyone find a clean solution for this?
The external React component says Uncaught TypeError: Cannot read property 'Component' of undefined when I link as npm package.
I link a package in package.json as "react-mapbox": "https://github.com/varya/react-mapbox.git". Then I use it in code
import {render} from 'react-dom';
import MapBox from "react-mapbox";
render(
<div>
<h1>Hello, world!</h1>
<MapBox />
</div>
,
document.getElementById('example')
);
But nothing works, I get that error. The full repo is here https://github.com/varya/react-mapbox-test I made a small example to illustrate.
The react-mapbox package is my own, maybe I build it wrongly? This is its repo https://github.com/varya/react-mapbox
I built it with webpack, like that https://github.com/varya/react-mapbox/blob/master/webpack.config.js As I suppose, this build does not include react package assuming that this will be at the project which link it. But the component still do not see react object.
UPD
I added import React from 'react'; as #aulizko suggested, but this only provided React object onto a page. It still was not visible for the component.
To fix this I had to provide this changes https://github.com/varya/react-mapbox/commit/2687d66025aaa84553a79850aa8686e88f1f39d9
I required react in the code of the component as well.
And I have to build with Babel. For some reason the webpack build gives the same error even if react is required. I created a branch to illustrate this https://github.com/varya/react-mapbox/tree/webpack Now I'm happy with Babel, but with this branch you can see what's wrong with webpack if interested.
You're probably bundling your module as UMD which is causing the bundle to utilized a global React variable which doesn't exist in the consumer app. You need to export the bundle as a CommonJS or AMD module using https://webpack.github.io/docs/configuration.html#output-librarytarget. Simple add libraryTarget: 'commonjs2 or libraryTarget: 'amd' to the output key in the webpack config and make sure you are importing react in your component.
I added import React from 'react'; as #aulizko suggested, but this only provided React object onto a page. It still was not visible for the component.
To fix this I had to provide this changes https://github.com/varya/react-mapbox/commit/2687d66025aaa84553a79850aa8686e88f1f39d9
I required react in the code of the component as well.
And I have to build with Babel. For some reason the webpack build gives the same error even if react is required. I created a branch to illustrate this https://github.com/varya/react-mapbox/tree/webpack Now I'm happy with Babel, but with this branch you can see what's wrong with webpack if interested.
The thing is that the jsx-code that you see in your editor is not the code that will be executed by node or browser.
If you look into code that are generated by the babel, you'll see something like this:
(0, _reactDom.render)(React.createElement(
'div',
null,
React.createElement(
'h1',
null,
'Hello, world!'
),
React.createElement(_reactMapbox2['default'], null)
), document.getElementById('example'));
So as you can see it uses React constant under the hood.
You need to explicitely import React if you want to use jsx-code.
Add something like this in your code and it'll work:
import React from 'react'; // <!--- add this!!!
import {render} from 'react-dom';
import MapBox from "react-mapbox";
// the rest of your code goes here...
You have to import React's Component it this way:
import {Component} from 'react';
or even:
import React, { Component, PropTypes } from 'react';