hot-module-loader apply cold to node_module package - reactjs

I'm trying to figure out how I can apply cold() to just a single node package.
according to the docs I need to use setConfig and also apply another babel-loader to include just node_modules. However I can't for the life of me figure out where or how to implement this.
import { setConfig, cold } from 'react-hot-loader'
setConfig({
onComponentRegister: (type, name, file) =>
file.indexOf('node_modules') > 0 && cold(type),
})
I'm using Kendo UI React which does not support HMR. So I need to wrap the PanelBarItem so that react-hot-loader doesnt wrap the component. What I would like to do is apply this rule all my kendo packages so I don't have to explicitly call cold on each component when I use it.
import React from 'react';
import { connect } from 'react-redux';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import messages from './messages';
import { Button } from '#progress/kendo-react-buttons';
import { PanelBar, PanelBarItem } from '#progress/kendo-react-layout';
import { changeLocale } from '../LanguageProvider/actions';
import { cold } from 'react-hot-loader';
class Home extends React.Component {
render() {
cold(PanelBarItem);
return (
<div>
<PanelBar title="Test">
<PanelBarItem title={'Sales Forecasts'}>
<PanelBarItem title={'Q1 sdfds'} />
<PanelBarItem title={'Q2 Forecast'} />
<PanelBarItem title={'Q3 Forecast'} />
<PanelBarItem title={'Q4 Forecast'} />
</PanelBarItem>
</PanelBar>
</div>
);
}
}

When you configure your webpack, you probably have something like this:
{
module: {
rules: [{
// testing for js/jsx files, and using babel-loader load them int webpack
test: /\.jsx?$/,
// Maybe looking only on your source folder
// (and looking aside from the node_modules as a consequence)
include: [
path.resolve(__dirname, '../src'),
],
use: [{
loader: 'babel-loader', // Ask babel to eat up those files and prep them for webpack
options: {
presets: [
// What ever babel presets you might use
],
plugins: [
// Some babel plugins you might use, like transform-runtime, or lodash
// This plugin is RHL's dude that goes over your code and marks
// things for patching later by the client
'react-hot-loader/babel',
]
},
}, {
// some other loaders for styles, images etc.
},]
}
// More webpack stuff
}
Usually, you would not apply the "js/jsx" loader to node_modules (as shown above) and this is why the babel plugin which RHL uses to patch things up never gets a chance to process the Kendo code.
What the documentation asks you to do it to add another loader that looks for js/jsx files but only applies the RHL babel plugin. like this:
{
module: {
rules: [{
// Your usual loaders including the usual babel-loader for your code
}, {
test: /\.jsx?$/,
include: [
// Focus on the folder of the module you want to "cold" later
// or go for all node_modules if you need to
path.resolve(__dirname, '../node_modules/<YOUR MODULE>'),
],
use: [{
loader: 'babel-loader',
options: {
plugins: [
// The only plugin
'react-hot-loader/babel',
]
},
}]
}
}
Then, when you configure RHL on the client (first thing you do) by calling setConfig you will also get the files from the now marked modules to apply cold on.
On your very very first file, just like they show in the documentation, require the rhlconfig.js file. The onComponentRegister should now also see files from node_modules.

Related

Module parse failedUnexpected token You may need an appropriate loader to handle this file type. | [duplicate]

My first time using react, so apologies if I'm doing something obvious and incredibly wrong. That said, I've read up on several similar-seeming bugs on here and on github and I can't find anything that works for mine. Here's the full error message:
ERROR in ./src/frontend/src/components/App.js 6:15
Module parse failed: Unexpected token (6:15)
You may need an appropriate loader to handle this file type.
| class App extends Component{
| render() {
> return <h1>React App</h1>
| }
| }
# ./src/frontend/src/index.js 1:0-35
The full code from which that error message was drawn:
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class App extends Component{
render() {
return <h1>React App</h1>
}
}
ReactDOM.render(<App />, document.getElementById('app'));
I feel like something is wrong with my webpack-config.js, but I copied that directly from a tutorial I was using so I'm not sure why it would be wrong. Here it is, for reference:
module.exports = {
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
}
]
}
}
And here are my package dependencies from package.json:
"dependencies": {
"prop-types": "^15.7.2",
"react": "^16.13.1",
"react-dom": "^16.13.1"
},
And finally my .babelrc
{
"presets": ["#babel/preset-env","#babel/preset-react"],
"plugins": ["transform-class-properties".js]
}
I really have no idea what's going on, so any help would be much appreciated. Please let me know if I left out any relevant info that could be helpful. Thank you.
The error comes from this line: return <h1>React App</h1>, because <h1>...</h1> is not valid javascript. Even if rename this is would be parsed as vanilla js and not jsx, because of your webpack-config.js, so there are multiple things you should do to fix it:
Rename App.js to App.jsx,
Update test: /\.js$/, to test: /\.(js|jsx)$/, in webpack-config.js
I think there is also an error in your .babelrc: you don't want that .js there, after "transform-class-properties".
Rename webpack-config.js to webpack.config.js
Here is a tutorial that shows this: https://www.valentinog.com/blog/babel/. Also, you could use https://github.com/facebook/create-react-app that simplifies all of this and provides a great starting config.
Added this code in webpack.config.js to resolve jsx as js.
Visit Can't resolve module (not found) in React.js
module.exports = {
//...
resolve: {
extensions: ['.js', '.jsx']
}
};

Is it possible to have javascript decorators (e.g. redux's #connect ) alongside ESbuild-loader

I'm using Webpack5 with ESbuild-loader for my React project's build pipeline.
For connecting my components to Redux store I use #connect decorator instead of using the HOC approach.
Example: MyComponent.jsx
#connect((state) => ({
notes: state.notes,
}))
class MyComponent extends PureComponent {
static propTypes = {
notes: PropTypes.arrayOf(PropTypes.object),
};
...
}
And here's my Webpack config rule for js/jsx files:
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
loader: 'esbuild-loader',
options: {
loader: 'jsx',
target: 'es2015',
},
},
When I try to start my dev server I get this error which is related to the line decorator is defined:
ERROR in ./project/MyComponent.jsx
Module build failed (from ./node_modules/esbuild-loader/dist/index.js):
Error: Transform failed with 1 error:
MyComponent.js:63:0: ERROR: Unexpected "#"
Does ESbuild not understand decorators?
According to library maintainer, this is not possible yet.
neither esbuild or esbuild-loader is advertised to support decorators.
Follow the discussion about future support here.

How to move css-in-js (Styled Components) to an external css files during build using webpack - ReactJS

I am trying to figure out where the CSS files are residing when I build the react project. I am using webpack and I am able to make a single CSS file for all the styles used throughout the project if I use normal CSS. When I use CSS in js using styled component, I am not getting an external CSS file.
webpack.config.js
var path = require('path');
var hwp = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
entry: path.join(__dirname, '/src/index.js'),
output: {
filename: 'index.js',
path: path.join(__dirname, './dist'),
publicPath : '/'
},
module:{
rules:[{
exclude: /node_modules/,
test: /\.js$/,
loader: 'babel-loader'
},
{
test: /\.css$/i,
use: [
{
loader : MiniCssExtractPlugin.loader,
options : {
publicPath: '/public/path/to/',
},
},
'css-loader'
]
}
]
},
devServer: {
historyApiFallback: true,
},
plugins:[
new hwp({template:path.join(__dirname, '/src/index.html')}),
new MiniCssExtractPlugin({
filename : '[name].css',
chunkFilename : '[id].css',
})
]
}
Contact.js
import React from 'react'
import styled from "styled-components"
const Container = styled.div`
background-color : red;
`
function contact() {
return (
<Container>
<h1>
Welcome to Contacts page
</h1>
</Container>
)
}
export default contact
This isn't supported by styled-components at the moment. From a project member -
We don't support static CSS extraction. You can try out emotion which does.
You might not need static CSS extraction actually, because of several reasons:
There's SSR which sends only critical CSS, instead of all static CSS, for the entire page. You don't even need to do SSR, but can use snapshotting (react-snapshot) or generate a static page (gatsby, et al), which basically saves a SSR result to a html.
Static extraction doesn't generate dynamic CSS, which means your page will either appear broken until the JS executes, or you'll need to defer until the JS is loaded
Caching doesn't actually buy you an advantage, because the JS bundles will likely always change in tandem with the extracted CSS
In v3 we will add preprocessing, which will actually a bigger advantage. As part of that we might support an option for static extraction, since the core library that will bring preprocessing will probably also be integrated into emotion, which does support extraction. So it might become an option. Or not 😉
Source
Emotion has also removed static css extraction
Duplicate of How can I opt for React Styled-Components to generate a physical CSS file?

How to use app's sass variables in decorators of storybook (React)

I've built a website with Gatsby.js (static website generator with React) and am trying to add storybook to it.
I added a custom webpack config to storybook (following the instruction at https://storybook.js.org/configurations/custom-webpack-config/) to load sass and sass-resources, but can't make it work.
Followings are the configurations. I have installed all of the "style-loader", "css-loader", "sass-loader", "sass-resources-loader" as well as "node-sass" for "storybook/react" in addition to those originally added to "gatsby" and "gatsby-plugin-sass" as dependencies.
It will be great if somebody kindly advise. Thank you very much for your help in advance.
structure
root - .storybook - addon.js
- config.js
- webpack.config.js
- src - components - Component_1 - Component_1.js
- Component_1.scss
- Component_1.stories.js
- ...
- styles - _variables.scss
- mixins - _mixin_1.scs
- ...
- ...
- ...
webpack.config.js (root/.storybook/webpack.config.js)
const path = require("path");
module.exports = {
module: {
rules: [
{
test: /\.scss$/,
loaders: [
"style-loader",
"css-loader",
"sass-loader",
{
loader: "sass-resources-loader",
options: {
resources: [
"src/styles/_variables.scss",
"src/styles/mixins/**/*.scss"
]
},
},
],
include: path.resolve(__dirname, "../")
}
]
}
};
component_1.stories.js
import React from "react";
import { storiesOf } from "#storybook/react";
import Component_1 from "./Component_1";
storiesOf("Component_1", module)
.addDecorator(story => (
<div style={{backgroundColor: $color-primary}}>
{story()}
</div>
))
.add("default", () => (
<Component_1>
This is Component 1!
</Component_1>
));
error message (shown on storybook app)
$color is not defined
ReferenceError: $grey is not defined
at http://localhost:6006/static/preview.bundle.js:80090:33
at http://localhost:6006/static/preview.bundle.js:57555:14
at http://localhost:6006/static/preview.bundle.js:57556:16
at WrapStory.render(http://localhost:6006/static/preview.bundle.js:61197:14)
at http://localhost:6006/static/preview.bundle.js:44767:21
at measureLifeCyclePerf (http://localhost:6006/static/preview.bundle.js:44047:12)
at ReactCompositeComponentWrapper._renderValidatedComponentWithoutOwnerOrContext (http://localhost:6006/static/preview.bundle.js:44766:25)
at ReactCompositeComponentWrapper._renderValidatedComponent (http://localhost:6006/static/preview.bundle.js:44793:32)
at ReactCompositeComponentWrapper.performInitialMount (http://localhost:6006/static/preview.bundle.js:44333:30)
at ReactCompositeComponentWrapper.mountComponent (http://localhost:6006/static/preview.bundle.js:44229:21)
In this case, sass variable "$color-primary" is defined in "src/styles/_variables.scss". I want to use it to style the Component_1 shown in the storybook app.
I tried importing "_variables.scss" expressly to "Component_1.stories.js" and failed again (Skiped "sass-resources-loader", just used "sass-loader").
Thank you for your advices.
[edit]
In addition to above, my storybook config file is as follow.
config.js (root/.storybook/config.js)
import { configure, addDecorator } from "#storybook/react";
// automatically import all files ending in *.stories.js
const req = require.context('../src/components', true, /\.stories\.js$/);
function loadStories() {
req.keys().forEach(filename => req(filename));
}
configure(loadStories, module);
There is a :export property for sharing variables. You can refer following link for sharing variables between sass and JavaScript.
https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
Try to add the path to your variables in the storybook config file
import "../src/styles/_variables.scss";

Trying to use css-loader with webpack to minimize our css

I've tried to go through a dozen or so different searches and read the docs on css-loader but I believe they aren't up to date.
I'm also trying to learn our react code and conventions coming from front end javascript / jquery so this is new for me.
What I want to do is take our css and minimize it using css-loader but I don't know how to do this from what I've read.
A piece of our current code looks like this - prod.config.js :
import webpack from 'webpack';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import PurifyCSSPlugin from 'purifycss-webpack-plugin';
import baseConfig from './base.config';
const PUBLIC_PATH = '//d1yepz0pwej23y.cloudfront.net/assets/' + process.env.TRAVIS_BUILD_NUMBER + '/';
export default {
...baseConfig,
output: {...baseConfig.output, publicPath: PUBLIC_PATH },
module: {
loaders: [
...baseConfig.module.loaders, {
test: /\.(woff|woff2|eot|ttf|otf|svg)(\?v=[0-9].[0-9].[0-9])?$/,
loader: 'file?name=[sha512:hash:base64:7].[ext]',
exclude: /node_modules\/(?!font-awesome)/
}, {
test: /\.(jpe?g|png|gif|svg)$/,
loader: 'file?name=[sha512:hash:base64:7].[ext]!image?optimizationLevel=7&progressive&interlaced',
exclude: /node_modules\/(?!font-awesome)/
}, {
test: /\.css$/,
loader: ExtractTextPlugin.extract('style', 'css?sourceMap!postcss'),
exclude: /node_modules/
}
]
},
plugins: [
// extract css
new ExtractTextPlugin('[name]-[chunkhash].css'),
// set env
new webpack.DefinePlugin({
'process.env': {
BROWSER: JSON.stringify(true),
NODE_ENV: JSON.stringify('production')
}
}), ...
...baseConfig.plugins
]
};
Is this enough to give me a suggestion on how to make this work? Or suggest where i can get some more info?
The docs say that I should require the css like this:
require("css-loader?minimize!./file.css")
but I'm not sure how to implement.
Thanks!
Update:
So after trying out what #Brandon mentioned, I actually saw code in our entry already that require's the css file.
if (process.env.BROWSER) {
require('styles/app.css');
}
I updated that to:
require('css-loader?minimize!styles/app.css');
but ended up with this error:
ERROR in ./~/css-loader?minimize!./app/styles/app.css
Module build failed: CssSyntaxError: /css-loader!/Users/homeImac/workspace/node_modules/style-loader/index.js!/Users/homeImac/workspace/node_modules/css-loader/index.js?sourceMap!/Users/homeImac/workspace/node_modules/postcss-loader/index.js!/Users/homeImac/workspace/app/styles/app.css:5:1: Unknown word
but that word is #import, does this make sense? If you guys can enlighten me on why this error is appearing, I'd appreciate it.
Thanks again!
So after trying to find solutions that solve the problem with loaders, I decided to look for another solution. A plugin called Purify CSS Plugin ended up being the answer.
new PurifyCSSPlugin({
purifyOptions: { info: true, minify: true }
})
Using the loader brought on a 'unknown word' error. Everything I tried either shifted the unknown word or did nothing to change the situation. All the folks online seemed to not be able to overcome this issue either.
Just proves the fact that there is usually more than one way to fix a problem.
put that require statement in one of your app's JavaScript source files. If it is a "global" css file, then your app's main entry JS file is a good candidate.
e.g. in app.js:
require("css-loader?minimize!./file.css"); // tell webpack about your css dependency so it can load and minimize it

Resources