Generating CSS modules for React components in Bit - javascript

We started sharing a number of React components in our SPA as Bit.dev components and ran into an issue: can't use our components on Bit's dashboard due to CSS-modules as Bit's build process does not create them. We use Bit 0.0.687. Use "bit start" to launch Bit dashboard or "bit export" to publish the components to a remote scope, then open a remote dashboard. Our components which use: import style from './style.css' and relay on a CSS module get undefined "style" under Bit. May someone tell, please, if there is a way to alter Bit's build process to generate CSS modules? In our Application's Webpack build we use:
module: {
rules: [
{
test: /\.css$/i,
include: /src/,
exclude: /node_modules/,
use: [
{
loader: require.resolve('style-loader', {
paths: [require.resolve('webpack-config-single-spa')],
}),
},
{
loader: require.resolve('css-loader', {
paths: [require.resolve('webpack-config-single-spa')],
}),
options: {
importLoaders: 1,
sourceMap: true,
modules: {
localIdentName: '[name]__[local]___[hash:base64:5]',
},
},
},
{
loader: 'postcss-loader',
options: {
sourceMap: true,
},
},
],
}
]}
and Webpack 5.x.

As Bit uses CRA under the hood, renaming CSS files to style.module.css helps. CRA recognizes "module" suffix and compiles these CSS as modules.

Related

PurgeCss remove necessary css with .ejs files

I'm using in my project bootstrap and webpack. I'm importing bootstrap library from source files, in this way I'm able to import only css and js component I need. However I want more advanced optimization for my css and I'm using purgecss too. Purgecss needs to point out pages that have html or injects html, into the content option of the plugin. I have this configuration in my
webpack.production.config.js
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
//prettier-ignore
plugins:[autoprefixer(),
purgecss({
content: [
"./src/**/index.ejs",
//"./dist/**/index.html",
//"./dist/**/*.js",
"./node_modules/bootstrap/js/src/popover.js",
"./src/**/*.js",
],
})],
},
},
},
],
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
plugins: [
autoprefixer(),
purgecss({
content: [
"./src/**/index.ejs",
//"./dist/**/index.html",
//"./dist/**/*.js",
"./node_modules/bootstrap/js/src/popover.js",
"./src/**/*.js",
],
}),
],
},
},
},
"sass-loader",
],
},
I'm using purgecss with postcss.
However the purgecss plugin seems doesn't recognize my index.ejs file and vital css is removed . If I cheat and I point out to my purgecss plugin the index.html file generated in the dist folder in the previous build it's all right. Then, purgecss can't handle .ejs files? Is there some workaround?
(Note that I have to indicate to the plugin the popover.js of the bootstrap library otherwise the css of the popover isn't included because it's a dynamic component not present in the html page but is added by popover.js)
(Note that my example is a minimal reproducible example to illustrate the problem)

Building an AngularJS and Vue.js into one app using webpack?

This may seem a bit convoluted, and potentially the answer is "don't do it that way, do it this way" so I'll start with the background of what I am doing. Basically I have a legacy AngularJS app that we want to migrate away from and towards Vue. We do not have the option to end-to-end rewrite the app, and need to do it piece by piece whilst still delivering a functional app.
The general goal is to therefore have both frameworks running simultaneously, my hope is that I can either do something with the routing or potentially split my single page app into 2 seperate pages for the different fraweworks. I have converted the angularjs from using a gulp build pipeline to using webpack as I assumed this was a logical first step to getting Vue to run, but now I have hit a road block.
My working webpack.config.js for building the angular app looks like the following:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
target: 'web',
// mode: "development",
// devtool: "source-map",
module: {
rules: [
{
test: /\.html$/,
loader: "html-loader",
},
{
test: /\.s[ac]ss$/i,
use: [
"style-loader",
"css-loader",
"sass-loader",
],
},
{
test: require.resolve("jquery"),
loader: "expose-loader",
options: {
exposes: ["$", "jQuery"],
},
}
],
},
entry: {
vendor: "./source/vendor.js",
main: "./source/index.js",
},
optimization: {
minimize: false
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'distribution'),
clean:true
},
plugins: [
new HtmlWebpackPlugin({
template: 'source/index.html',
})
]
};
this now works fine and I get something out add the end that works as it did before.
I then added a /source/vueJs directory, and copy & pasted the content hello world project that is generated by vue create hello-world. My assumption was if I could modify my webpack.config.js to build this, I could then iterate on it further to get to a point where it merged the two working apps together, but I'm already struggling to get the hello-world vue project to produce anything.
So far I basically commented out all the relevant angularJS parts, and added what I thought was correct to get the vue app to build, so now I have this:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
target: 'web',
mode: "development",
devtool: "source-map",
module: {
rules: [
// {
// test: /\.html$/,
// loader: "html-loader",
// },
// {
// test: /\.s[ac]ss$/i,
// use: [
// "style-loader",
// "css-loader",
// "sass-loader",
// ],
// },
// {
// test: require.resolve("jquery"),
// loader: "expose-loader",
// options: {
// exposes: ["$", "jQuery"],
// },
// },
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
},
],
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
// this will apply to both plain `.js` files
// AND `<script>` blocks in `.vue` files
{
test: /\.js$/,
loader: 'babel-loader'
},
// this will apply to both plain `.css` files
// AND `<style>` blocks in `.vue` files
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
}
],
},
entry: {
// vendor: "./source/vendor.js",
// angular: "./source/index.js",
vue: "./source/vueJs/index.js"
},
optimization: {
minimize: false
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'distribution'),
clean:true
},
plugins: [
new HtmlWebpackPlugin({
//template: 'source/index.html',
}),
new VueLoaderPlugin()
],
};
this runs fine and I get a distribution/ directory with my assets in, but the served site runs as if there is no javascript running at all. Comparing the output of npx webpack on my version and the output of npx vue-cli-service build on the hello-world project, the javascript is similar but different in a lot of key areas, for a start it seems as though my version does not have any HTML embedded in it like the hello world project does.
Is it a lost cause trying to compile a vue app from webpack? Can you only do it using vue-cli-service build and therefore limited to vue only? I tried modifying my vue.config.js using the info found at https://cli.vuejs.org/guide/webpack.html & https://cli.vuejs.org/config/, but frankly I feel I am out of my depth at this point and unsure if what I am doing is even a good idea.
Is there a better strategy to take to get to my end goal? If this is a workable solution, what do I need to change about my configs to get both the angularjs and the vue app to build properly?
I wasn't seeing the wood for the trees. The problem isn't that that webpack.config.js doesn't succesfully producing a working angular & vue combined app, the problem is that I'm not providing a template that actually uses either of these things, so it just produces a blank index.html with the scripts provided but no content in the body.
Changing the
new HtmlWebpackPlugin({
//template: 'source/index.html',
}),
in my question to have a template that uses both an AnularJS component and a Vue component worked fine.

Enable css module in react 16.7

I am learning react looking videos but in one video they are enabling css module by eject>edit webpack.config.dev.js but i can't find the same file in my react , later i came to know that in 16.7 its different so can anyone tell the steps to enable css module in react 16.7
fortunately in react 16.8 no need to run "npm run eject" and you can just add extention ".module.css" in place of ".css" to get the sake of CSS module
To enable CSS module, first of all go to your project directory then open command line and run npm run eject
inside the config folder you will find webpack.config.dev.js and webpack.config.prod.js files.open those files
and add this code to webpack.config.dev.js
{
test: cssRegex,
exclude: cssModuleRegex,
use: getStyleLoaders({
importLoaders: 1,
modules: true,
localIdentName: '[name]__[local]__[hash:base64:5]'
}),
},
and in filewebpack.config.prod.js add
test: cssRegex,
exclude: cssModuleRegex,
loader: getStyleLoaders({
importLoaders: 1,
modules: true,
localIdentName: '[name]__[local]__[hash:base64:5]',
sourceMap: shouldUseSourceMap,
}),
After saving this you can now use CSS module
For react version 16.13
In webpack.config.js file find this keyword 'css-loader'.
You will find below code in line number 82 for react version-16.13
{
loader: require.resolve('css-loader'),
options: cssOptions,
}
Replace above object with
{
loader: require.resolve('css-loader'),
options: {
modules: {
mode: "local",
localIdentName: "[name]_[local]_[hash:base64:5]"
},
import: true,
importLoaders: true
}
}
Start the server again by npm start(If changes are not reflected)

webpack live hot reload for sass

I am building a workflow for a react starter and would like to have my browser auto reload when I make a change to my scss files.
Currently, webpack will hot reload when I make a change in my index.js file (set as my entry point). However when I change/add scss code in my scss file, it gets compiled, but the css doesn't get output anywhere and does not trigger a browser reload.
I am new to webpack would really appreciate some insight here.
Here is my webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: ['./src/js/index.js', './src/scss/style.scss'],
output: {
path: path.join(__dirname, 'dist'),
filename: 'js/index_bundle.js',
},
module: {
rules: [
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.scss$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].css',
outputPath: 'css/'
}
},
{
loader: 'extract-loader'
},
{
loader: 'css-loader'
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
]
}
My index.js entry point file
import React from 'react';
import ReactDOM from 'react-dom';
import App from '../components/App';
ReactDOM.render(
<App/>,
document.getElementById('App')
);
And my App component
import React, {Component} from 'react';
import '../../dist/css/style.css';
class App extends Component {
render() {
return (
<div>
<p>Test</p>
</div>
)
}
}
export default App;
Actually, style-loader is the one that is responsible for CSS HMR.
You should add it at the end of the style pipeline, only for dev.
For production, you can remain your config.
It should look something like that:
const devMode = process.env.NODE_ENV !== 'production'
{
test: /\.scss$/,
use: [
devMode ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
},
{
loader: 'postcss-loader'
},
{
loader: 'sass-loader'
}
]
}
Pay attention, the best practice of extracting css into a separate file is to use MiniCssExtractPlugin if you are using webpack 4, or ExtractTextWebpackPlugin, if you are using webpack < 4.
Try using Parcel instead of Webpack. I used to spend hours configuring Webpack to get things like hot reload working. With Parcel, most things just "work" without a configuration file. For example, I wanted to start using Pug templates. Parcel recognized the .pug extension and automatically downloaded the required NPM dependencies!
In your case, just include the SCSS file in your app like this: import '../scss/style.scss' (notice the path is to the .scss source file relative to index.js). Parcel will automatically do the "sensible" thing.
Here are some references to get started with Parcel + React + SASS:
Build a React web app with Parcel.js lightning fast
Parcel SCSS documentation
Notable advantages and disadvantages of Parcel vs WebPack:
Parcel requires minimal configuration; often no configuration.
Parcel usually builds much faster than WebPack.
The WebPack dev server seems more stable. (The Parcel dev server needs to restarted once in a while and doesn't play nice with Dropbox. Apparently this should be fixed in version 2.0.)
When (an uncommon) configuration is required, it might not be obvious how to do that in Parcel; at least in WebPack, all the configuration is in one place.
Sometimes Parcel's automatic configuration does thing people don't expect, confusing them.

Multiple package.jsons with ES6 Babel

I have a large project that I would like to divide up into multiple package.json's so that the dependencies for each part can be clearly stated and so those packages can be exported as individual parts.
However, I want my app to include each of these packages and compile them using webpack and babel. There are shared dependencies for the packages, so I don't want to just output each one to a /dist folder.
My ideal directory structure looks like this:
\main
\app
\node_modules
package.json
\package1
package.json
node_modules
index.js
\package2
package.json
node_modules
index.js
I tried multiple approaches:
Using webpack's resolve modules with something like path.resolve('app'). This just doesn't work, even though it should in theory.
Using main's package.json to reference others using "package1" : "file:../package1". This doesn't treat package1 as es6 javascript and throws errors. Using resolveLoaders in the webpack configuration does not help.
The webpack config I have is as follows.
module: {
loaders: [
{
test: /\.js?/,
loader: 'babel-loader',
include: [
path.resolve('app'),
path.resolve('../prose'),
],
query: {
plugins: [
['react-transform', {
transforms: [{
transform: 'react-transform-hmr',
// If you use React Native, pass 'react-native' instead:
imports: ['react'],
// This is important for Webpack HMR:
locals: ['module']
}]
}],
['transform-object-assign']
]
}
},
{ test: /\.css$/, loader: 'style-loader!css-loader!sass-loader' },
{ test: /\.svg$/, loader: 'file-loader' },
{ test: /\.png$/, loader: 'file-loader' },
{ test: /\.jpg$/, loader: 'file-loader' },
{ test: /\.json$/, loader: 'json-loader' }
]
},
resolve: {
modules: [
path.resolve('app'),
'node_modules',
],
extensions: ['.json', '.js', '.jsx'],
}
Any thoughts or examples of other projects that do this would be appreciated!
You should check out lerna. It enables you to use multiple package.jsons and even packages in one repo. It might help you with you requirements.

Categories