React + Reactstrap + CSS Modules + Webpack - reactjs

I've been looking how I can combine the following : ReactJS + ReactStrap and CSS-Modules (react-css-modules and/or boostrap-css-modules), however, I can't seem to piece the three modules together to achieve the desired effect (or find any help online).
The idea behind this is to have the ReactStrap elements available, i.e. :
import React from 'react';
import { Button } from 'reactstrap';
export default (props) => {
return (
<Button color="danger">Danger!</Button>
);
};
but also allow me to use CSS-Modules for the end result being something similar to :
import React from 'react';
import CSSModules from 'react-css-modules';
import styles from './mybutton.css';
class Test extends React.Component {
render () {
return <Button color='danger' styleName='myButton'>Danger</div>;
}
}
export default CSSModules(Table, styles);
where mybutton.css could be something like :
.myButton {
composes: btnPrimary from "bootstrap-css-modules/css/buttons.css";
background-color: dodgerblue;
border-color: dodgerblue;
}
I'm also using Webpack so I don't even know where to begin with regards to using it with Webpack.
Edit :
The way I am using this is as follows :
npm install --save bootstrap#4.0.0-alpha.6
npm install --save reactstrap react-addons-transition-group react-addons-css-transition-group react react-dom
npm install --save bootstrap-css-modules
Here is my webpack config
const webpack = require('webpack');
const path = require('path');
const HtmlwebpackPlugin = require('html-webpack-plugin');
const ROOT_PATH = path.resolve(__dirname);
module.exports = {
devtool: process.env.NODE_ENV === 'production' ? '' : 'source-map',
entry: [
path.resolve(ROOT_PATH, 'app/src/index'),
],
module: {
rules: [
{
enforce: 'pre',
test: /\.jsx?$/,
loader: process.env.NODE_ENV === 'production' ? [] : ['eslint-loader'],
include: path.resolve(ROOT_PATH, 'app'),
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
loader: 'babel-loader',
query: {
presets: ['react'],
},
},
{
test: /\.scss$/,
loaders: ['style-loader', 'css-loader', 'sass-loader'],
}],
},
resolve: {
extensions: ['.js', '.jsx'],
},
output: {
path: process.env.NODE_ENV === 'production' ? path.resolve(ROOT_PATH, 'app/dist') : path.resolve(ROOT_PATH, 'app/build'),
publicPath: '/',
filename: 'bundle.js',
},
devServer: {
contentBase: path.resolve(ROOT_PATH, 'app/dist'),
historyApiFallback: true,
hot: true,
inline: true,
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new HtmlwebpackPlugin({
title: 'testapp',
}),
],
};
Thanks

#tehOwner ...phew this question was a doozy. I think I accomplished what you were trying to do.
I created a sandbox that can be found here.
DEMO
Basically, you need this npm module in your project to be able to assign multiple CSS classes to a react component using the className property.
And setup your component with a structure that resembles the below
import React, { Component } from 'react';
import { Button } from 'reactstrap';
import CSSModules from 'react-css-modules';
import styles from './MyDangerButton.css';
import cn from 'classnames';
class MyDangerButton extends Component {
render() {
const myFancyDangerButton = cn({
btn: true,
'btn-danger': true,
MyDangerButton: true
});
return (
<div>
<h1>My Fancy Danger Button!</h1>
<Button className={myFancyDangerButton}>Danger Button</Button>
</div>
);
}
}
export default CSSModules(MyDangerButton, styles);
🍺 cheers
Chris

The newest solution is to upgrade the react-script by using:
npm upgrade --latest react-scripts
It supports the CSS module so you don't need to config anything.
What need to do is add .module to the CSS file: from './mybutton.css' to './mybutton.module.css'. And change the import as well:
import styles from './mybutton.module.css';
Using this, we don't need to perform
npm run eject
any more.

Related

Building styling in an Azure DevOps extension

My extension does not contain any css files when I build it and I don't know what makes it do that. I did not change the Common.tsx that was scaffolded. Neither my own styles or the Azure DevOps UI styling gets packaged or used by components.
Azure DevOps UI documentation says to do this:
https://developer.microsoft.com/en-us/azure-devops/develop/extensions
When consuming the 2.164.0 version or later of the azure-devops-ui package, extensions should import the Azure DevOps global styles in order to get the same look and feel (font family, font sizes, hyperlink treatment, etc.) of Azure DevOps pages. This can be done with the following import:
import "azure-devops-ui/Core/override.css";
This is already done in the Common.tsx by default however.
directory structure
src
│ Common.scss
│ Common.tsx
│
└───Components
└───RESTRequestButton
RESTRequestButton.html
RESTRequestButton.json
RESTRequestButton.scss
RESTRequestButton.tsx
webpack.config.js
const path = require("path");
const fs = require("fs");
const CopyWebpackPlugin = require("copy-webpack-plugin");
const entries = {};
const ComponentsDir = path.join(__dirname, "src/Components");
fs.readdirSync(ComponentsDir).filter(dir => {
if (fs.statSync(path.join(ComponentsDir, dir)).isDirectory()) {
entries[dir] = "./" + path.relative(process.cwd(), path.join(ComponentsDir, dir, dir));
}
});
module.exports = {
entry: entries,
output: {
filename: "[name]/[name].js"
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
alias: {
"azure-devops-extension-sdk": path.resolve("node_modules/azure-devops-extension-sdk")
},
},
stats: {
warnings: false
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: "ts-loader"
},
{
test: /\.s[ac]ss?$/,
use: ["style-loader", "css-loader", "azure-devops-ui/buildScripts/css-variables-loader", "sass-loader"]
},
{
test: /\.css?$/,
use: ["style-loader", "css-loader"],
},
{
test: /\.woff?$/,
use: [{
loader: 'base64-inline-loader'
}]
},
{
test: /\.html?$/,
loader: "file-loader"
}
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: "**/*.html", context: "src/Components" }
]
})
]
};
Common.tsx
import "azure-devops-ui/Core/override.css";
import "es6-promise/auto";
import * as React from "react";
import * as ReactDOM from "react-dom";
import "./Common.scss";
export function showRootComponent(component: React.ReactElement<any>) {
ReactDOM.render(component, document.getElementById("root"));
}
RESTRequestButton.scss
#import "node_modules/azure-devops-ui/Core/_platformCommon.scss";
RESTRequestButton.tsx (only how I import the styling and how I reference Common.tsx)
import "./RestRequestButton.scss";
import { showRootComponent } from "../../Common";
class RESTRequestButton extends React.Component<{}, {}> {
//a lot of code goes here
}
export default RESTRequestButton;
showRootComponent(<RESTRequestButton />);
The solution was to bump package versions. I set package style-loader to "^3.3.1" and it was fixed.

Moment is not defined when using React with Webpack

I'm in the progress of "Reactifying" a PHP application and am adding a single component to start (with several child components). In addition to the custom components, there are several library dependencies (react-bootstrap, moment, etc).
I'm using webpack to compile it and it compiles correctly and generates the dist/main.js as expected. However, when adding it to the HTML template I get the error "moment is not defined", though the "react-bootstrap" dependencies appear to load correctly. Based on the guidance in https://github.com/palantir/blueprint/issues/959, I tried both import * as moment from 'moment', import moment from 'moment' as well as the const moment = require('moment'); I had previously been using which compiled fine with browserify.
webpack.config.js
const path = require('path')
module.exports = {
mode: 'development',
context: path.resolve(__dirname, 'components'),
entry: './dir/EntryComponent.app.jsx',
resolve: {
extensions: ['.jsx', '.json', '.js']
},
optimization: {
minimize: false
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
}
};
.babelrc
{
"presets": ["#babel/preset-env", "#babel/preset-react"]
}
Component.jsx
import Collapse from "react-bootstrap/Collapse";
import moment from 'moment';
const Datetime = require('react-datetime');
...
<label>Start</label>
<Datetime
value={this.props.startDate}
placeholder="Start Date"
dateFormat='YYYY-MM-DD'
timeFormat={false}
input={true}
viewDate={moment().subtract(1, 'month')}
onChange={date => this.props.updateStartDate(date)}
closeOnSelect={true}
closeOnTab={true}
viewMode="months"
inputProps={{readonly: 'readonly'}}/>

Addng css files in React project with Webpack 4

I am building a simple React app from scratch using Webpack.
I was finally able to run the dev server and when I tried to apply some styles via CSS, the files wouldn't load and I assume my Webpack 4 configuration is not right.
Here is the code:
webpack.config.js
// const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const path = require('path');
module.exports = {
mode: 'development',
entry: ['./src/index.js'],
resolve: {
extensions: [".js", ".jsx"]
},
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist',
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
port: 8080
},
module: {
rules: [
{
test: /\.js|.jsx$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: ["react"]
}
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.(png|jpg)$/,
loader: 'url-loader'
}
]
},
};
My project structure is like this, I will include only src because it lives in the root:
**src**
|_assets
|_componentns
|_styles
|_App.css
|_index.css
App.jsx
index.js
index.html
I would like to be able to add multiple css files for each component I have and apply them, and to be able to style the index the index.html.
Thank you very much for your help.
Your webpack configuration looks fine.
make sure you import the required css files in your components.
import "./App.css";
class App extends Component {
render() {
return (
<div>
<Child />
</div>
);
}
}
All you have to do is import the CSS files when needed as you would a JavaScript module. So if you want to have a style sheet for your whole application, you can import a global stylesheet in your index.js.
import './styles/index.css';
and you can do the same for each component with specific styles
import './styles/App.css'
in which case you might want to setup CSS modules to avoid overlapping class names.
Ok, rookie mistake here, the way I ahve set up webpack is I have to build it first and then run the dev server, no the other way around.
All answers above are valid and helpful, I just forgot to run build after changes.

Webpack 4: Module parse failed: Unexpected token

During my builds, webpack is giving me this error:
ERROR in ./client/components/App/index.tsx 15:9
Module parse failed: Unexpected token (15:9)
You may need an appropriate loader to handle this file type.
|
|
> const App: SFC = () => (
| <div style={{ background: "red" }}>
| <h3>test</h3>
# ./client/index.tsx 11:4-14:6 12:24-51
# multi react-hot-loader/patch ./client/index.tsx webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true
Here is my webpack.config.ts:
import CleanWebpackPlugin from "clean-webpack-plugin";
import HtmlWebpackPlugin from "html-webpack-plugin";
import path from "path";
import { Configuration, HotModuleReplacementPlugin } from "webpack";
const rootDir = ["..", "..", "..", ".."];
const distDir = ["..", ".."];
// this file lives in one place as `.ts` and another as `.js` grab the
// file extension to determine the include path relative to its location
const include =
path.extname(module.id) === ".ts"
? path.resolve(__dirname, "client", "index.tsx")
: path.resolve(__dirname, ...rootDir, "client", "index.tsx");
const exclude = /node_modules/;
const tsconfig = path.resolve(
__dirname,
...rootDir,
"config",
"tsconfig.client.json"
);
// development plugins
const plugins = [
new HotModuleReplacementPlugin(),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "..", "..", "..", "index.html")
}),
new CleanWebpackPlugin([path.resolve(__dirname, ...distDir, "*.*")], {
allowExternal: true,
root: __dirname,
verbose: true
})
];
// script for webpack-hot-middleware
const hotMiddlewareScript: string =
"webpack-hot-middleware/client?path=/__webpack_hmr&timeout=20000&reload=true";
const webpackDevConfig: Configuration = {
context: path.resolve(__dirname, ...rootDir),
devtool: "source-map",
entry: {
app: ["react-hot-loader/patch", include, hotMiddlewareScript]
},
mode: "development",
module: {
rules: [
{
exclude,
include,
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
exclude,
include,
loader: "ts-loader",
options: {
configFile: tsconfig,
transpileOnly: true
},
test: /\.tsx?$/
},
{
enforce: "pre",
exclude,
include,
loader: "source-map-loader",
test: /\.js$/
}
]
},
optimization: {
nodeEnv: "development"
},
output: {
filename: "[name].bundle.js",
path: path.join(__dirname, ...distDir),
publicPath: path.join(__dirname, ...distDir, "static/")
},
plugins,
resolve: {
extensions: [".js", ".ts", ".tsx", "*"]
},
target: "web"
};
export default webpackDevConfig;
My App.tsx:
import React, { SFC } from "react";
import ReactDOM from "react-dom";
const App: SFC = () => (
<div style={{ background: "red" }}>
<h3>test</h3>
</div>
);
My index.tsx:
import React from "react";
import ReactDOM from "react-dom";
import { App } from "./components";
ReactDOM.render(<App />, document.getElementById("app"));
// enables Hot Module Replacement (HMR)
if ((module as any).hot) {
(module as any).hot.accept("./components/App", () => {
// for HMR to work, `App` must be re-required
const NextApp = require("./components/App").default;
ReactDOM.render(<NextApp />, document.getElementById("app"));
});
}
My tsconfig.json:
{
"compilerOptions": {
"allowJs": true,
"jsx": "react",
"module": "commonjs",
...
}
}
The error itself seems to give the solution: You may need an appropriate loader to handle this file type., however, it is my understanding that ts-loader should be able to handle react.
Here is an example webpack.config provided by the ts-loader team used in an app that uses typescript and react. The set up is fairly similar to my own, however, I do not use webpack-dev-server, rather, I use webpack-dev-middleware.
The issue was resolved by niba's comment on the original question. It seems that ts-loader when given a single module to include will not traverse the linked modules. Removing the include field or using the folder name fixed this error for me.

unable to use styles from local css file

I am creating reactjs web app where I am trying to use styles from a local css file. Source code is given for reference.
/src/css/aboutcompany.css
.center {
text-align: center;
color: red;
}
/src/AboutCompany.js
import React,{Component} from 'react';
import style from './css/aboutcompany.css';
class AboutCompany extends Component{
render(){
return(
<div>
<p className="style.center"> Company</p>
<hr/>
Technologies is leading Company providing end to end software solutions to customers globally. We are specialized in every vertical of industries and deliver quality solutions using latest technologies.
</div>
)
}
}
export default AboutCompany;
webpack.config.js
var config = {
entry: './src/index.js',
output: {
path:'/build/',
filename: 'index.js',
},
devServer: {
inline: true,
port: 8081,
historyApiFallback: true
},
module: {
rules: [
{
test: /\.(jpg|png|svg)$/,
use: 'url-loader'
},
{
test: /\.jsx?$/,
exclude: /node_modules/,
use: 'babel-loader'
},
{
test: /\.css$/,
use: 'css-loader'
}
]
}
}
module.exports = config;
As you can see in the AboutCompany.js here <p className="style.center"> Company</p> we are trying to use css class center , but it does not work. Can someone tell me where am I wrong.
To make use of css modules in development first you need to install style-loader:
$ npm install style-loader --save-dev
then in your configurations pass modules=true as an option to css-loader
{
test: /\.css$/,
use: ['style-loader', 'css-loader?modules=true']
}
finally in your jsx code you can call your classes like this:
<p className={styles.center}/>
and you are done.

Resources