Importing styles from meteor into React Storybook - javascript

I am trying to set up react storybook with my meteor 1.4 project that has the package twbs:bootstrap3 and some custom styles.
After reading the info from the link to set up styles here I have the following code:
const path = require('path');
module.exports = {
module: {
loaders: [
{
test: /\.less?$/,
loader: ["style", "css", "less"],
include: path.resolve(__dirname, '../'),
},
{
test: /\.css?$/,
loader: ["style", "raw"],
include: path.resolve(__dirname, '../'),
},
}
}
Here is my story
import React from 'react';
import { storiesOf, action } from '#kadira/storybook';
import { styles } from './shared';
import HomeSearch from '../features/Search/components/HomeSearch/HomeSearch.jsx';
storiesOf('HomeSearch', module)
.add('normal', () => {
return getItem();
});
function getItem() {
return <HomeSearch />
}
But I am not sure how to import those "packed" styles into the stories.

If the CSS is pre-compiled, and global, you can add the tags in a custom preview-head.html file. see: https://storybook.js.org/configurations/add-custom-head-tags/
If the CSS is non global, or needs to be processed, you need to add the correct loaders to the custom webpack config. see https://storybook.js.org/configurations/custom-webpack-config/

Related

Webpack bundled library does not compile in React

I'm trying to bundle a standalone library with Webpack (v5) and use it in my React application.
The webpack.config.js file is pretty straightforward:
const path = require('path');
const webpack = require('webpack');
module.exports = {
entry: './TestWebpack.js',
mode: process.env.NODE_ENV === 'production' ? 'production' : 'development',
output: {
filename: 'widgets.bundle.js',
path: path.join(__dirname, '..', 'ClientApp', 'src', 'dynamicBundles'),
library: {
name: 'widgets',
type: 'umd',
umdNamedDefine: true,
}
},
externals: {
'react': {
'commonjs': 'react',
'commonjs2': 'react',
'amd': 'react',
'umd': 'react'
},
'react-dom': {
'commonjs': 'react-dom',
'commonjs2': 'react-dom',
'amd': 'react-dom',
'umd': 'react-dom'
}
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: [
'#babel/preset-react'
],
}
}
},
]
},
};
The TestWebpack.js file is also very simple:
import React from 'react';
export default function TestWebpack(){
return (
<div>Test</div>
)
}
But when I compile it with Webpack and use it in my React application like this:
import React from 'react'
import { useEffect } from 'react'
import * as Widgets from '../dynamicBundles/widgets.bundle'
export default function TestUsingWebpack(){
useEffect(() => {
console.log('Object.keys(Widgets) - ', Object.keys(Widgets));
}, []);
return <div>Test</div>
}
I get the following errors:
Line 12: 'define' is not defined no-undef
Line 13: 'define' is not defined no-undef
Line 18: Unexpected use of 'self' no-restricted-globals
I can't figure out how to solve this. I see in the bundled file that in these lines an undefined variable 'define' is used. I saw in other answers that people put lines at the start to define it properly, but this bundle may change frequently so it's not an answer.
Maybe there's something wrong with my Webpack config file? I'm new to this and tried following the newest articles and Webpack documentation about standalone library but it's still not working.

webpack can't parse material ui button in a child component

I'm trying to bundle some React components with webpack.
But when I launch webpack --mode=development, i get this error :
Module parse failed: Unexpected token (6:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
| const OwnButton = () => {
| return ( <Button color='secondary' variant='outlined'
This is my webpack config :
const path = require('path');
module.exports = {
entry: './src/app.js', // relative path
output: {
path: path.join(__dirname, 'public'), // absolute path
filename: 'js/bundle.js' // file name
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
}
]
}
};
This is my app.js config :
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import Button from '#material-ui/core/Button';
import OwnButton from './Components/OwnButton';
const template = <Button>Hello from react jsx</Button>;
ReactDOM.render(template, document.getElementById('root'));
ReactDOM.render(<OwnButton/>, document.getElementById('React-OwnButton'));
And the wanted component (index.jsx) :
import Button from '#material-ui/core/Button';
const OwnButton = () => {
return (
<Button color='secondary' variant='outlined'>
Hello from my own component
</Button>
);
};
export default OwnButton;
And my .babelrc
{
"presets": ["#babel/preset-env", "#babel/preset-react"]
}
I don't understand how the call l.6 on app.js can work but not the on index.jsx l.6.
Where must I put the loader for this, in babel?
The problem is that you configured the Babel Loader to only intervene for .js files.
Try changing: test: /\.js$/ -> test: /\.((js)|(jsx))$/
This will make the loader work for .jsx files too.

How to embed React component on other sites?

I've created React application and I need to generate embed code to other websites. It's large app where I want to do only one component as a widget for other domains. I have read Writing embeddable Javascript plugin with React & Webpack and How to embed react component on other domains?. I set my webpack, but still can't render the widget on another domain.
This widget should:
be available via <script> tag, not iframe
show only one part of the app (path /referral), but not all app
The widget is a button and popup, which displays by click on the button.
Here is my webpack.config.js in client folder:
const path = require('path');
const bundleOutputDir = './referral';
const env = require('yargs').argv.env;
module.exports = env => {
const isDevBuild = !(env && env.prod);
if (env === 'build') {
mode = 'production';
} else {
mode = 'development';
}
return [
{
mode: mode,
entry: './src/components/early-referrals/Referral.js',
output: {
filename: 'widget.js',
path: path.resolve(bundleOutputDir),
library: 'Referral',
libraryTarget: 'umd',
umdNamedDefine: true
},
devServer: {
contentBase: bundleOutputDir
},
module: {
rules: [
{ test: /\.html$/i, use: 'html-loader' },
{
test: /\.css$/i,
use: [
'style-loader',
'css-loader' + (isDevBuild ? '' : '?minimize')
]
},
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader'
}
]
},
{
test: /(\.jsx|\.js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
'#babel/env',
{
targets: {
browsers: ['ie 6', 'safari 7']
}
}
]
]
}
}
}
]
}
}
];
};
Here is component RegisterReferral.js, which is entry point in webpack:
import PopupRef from '../popup/PopupRef';
const RegisterReferral = ({
...
}) => {
const [...] = useState();
useEffect(() => {
...
}, []);
return (
<div>
// some styles for button that displays popup
<PopupRef />
</div>
);
};
const mapStateToProps = state => ({
...
});
export default connect(
mapStateToProps,
{ ... }
)(RegisterReferral);
PopupRef.js is a component with popup, which should displays on other websites within the button.
In the App.js, I have the route for this component that I want to create as an embeddable:
<Route exact path="/referral" component={RegisterReferral} />
And this is a way how I paste the code on another domain:
// the URL in script is an URL of bundle file from webpack
<html>
<head>
<script src="http://example.com/client/referral/widget.js" type="text/javascript"></script>
</head>
<body>
<p>Another website</p>
<div id='app'></div>
</body>
</html>
Also, I've tried to do entry point in webpack.config.js with Referral.js. And here is this component:
// Referral.js
import React from 'react';
import { render } from 'react-dom';
import App from './RegisterReferral.js';
render(<App />, document.getElementById('app'));
// At this case, webpack.config.js has 2 changes:
entry: './src/components/early-referrals/Referral.js',
output: {
...
library: 'Referral',
},
Nothing works. My component doesn't display on other websites.
Please help me to figure out what's wrong and how to embed one component (not all app) from React app on other websites.
Assume that you correctly config your webpack to bundle react js code
This is how I render the component in any page I want
Assume that I have this component
import React, {Component} from "react";
import {render} from "react-dom";
class LoginForm extends Component { }
render(<LoginForm/>, document.getElementById("loginForm")); // use render method
Edit:
Just saw your code I think you need also change the id in index.html
<div id="root"></div>
to
<div id="referral"></div>

React doesn't append class from className

I have a problem with React and don't know why, but React doesn't appent the attribute class in rendered HTML code. I import css file in body, import styles in react script, write className attribute, etc..
The result on page will be block without class – <div>test</div>
In App.js
import React, {Component} from 'react';
import styles from '../assets/main.css';
export default class App extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div className={styles.test}>test</div>
</div>
);
}
}
In main.css
.test {
color: red;
}
Webpack config
const HTMLWebpackPlugin = require('html-webpack-plugin');
const HTMLWebpackPluginConfig = new HTMLWebpackPlugin({
template: __dirname + '/app/index.html',
filename: 'index.html',
inject: 'body'
});
const webpack = require('webpack');
module.exports = {
entry: [
'react-hot-loader/patch',
__dirname + '/app/index.js'
],
devServer: {
hot: true
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader'
},
{
test: /\.css$/,
loader: "style-loader!css-loader"
}
]
},
output: {
filename: 'transformed.js',
path: __dirname + '/build'
},
plugins: [
HTMLWebpackPluginConfig,
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
],
resolve: {
extensions: ['.js', '.jsx', '.css']
}
};
Importing your CSS stylesheet just causes Webpack to bundle it along with the rest of your JavaScript. You can't add styles.test as an attribute, that won't do anything. You need to specify the className as a string, just like you would for an HTML element.
render() {
return (
<div>
<div className="test" >test</div>
</div>
);
}
I think you should try importing your main.css file in your entry file i.e app/index.js. You don't need to add {styles.test} in className.
import './assets/main.css';
When the webpack bundle will run it will take all your css.
You just need to give same className like :
<div>
<div className='test'>test</div>
</div>
Also, make sure you have installed all loaders like file-loader, css-loader, url-loader, style-loader and included them in your webpack.config file.

Use babel-loader and raw-loader together

I have webpack config
{
// ...
module: {
rules: [
{
resource: {
not: [/node_modules/, /raw-loader/],
and: [/\.js$/]
},
loader: 'babel-loader'
}
]
}
}
Some component
import React from 'react';
import { H1 } from '../../../components/Typography';
const Example = () => {
return <H1>H1 — Header</H1>;
};
export default Example;
And file that imports this example component
import ExampleH1Code from 'raw-loader!./examples/h1';
import ExampleH1 from './examples/h1';
Babel applies to both ExampleH1 and ExampleH1Code. But i want ExampleH1Code to be raw ES6 text ExampleH1 working component to render on page.
Is it possible? Thanks

Categories

Resources