Using tailwindcss with React, size not decreased after purging - reactjs

I'm tried to set up tailwind with ejected create-react-app. I'm successful to make it works but failed to purge the size. here is my setup
./src/assets/styles/tailwind.css
#tailwind base;
#tailwind components;
#tailwind utilities;
postcss.config.js
module.exports = {
plugins: [
require('tailwindcss'),
require('autoprefixer')
],
};
tailwind.config.js
module.exports = {
purge: ["./src/**/*.js"],
theme: {
extend: {}
},
variants: {},
plugins: []
};
package.json
"scripts": {
"start": "node scripts/start.js && postcss src/assets/styles/tailwind.css -o src/assets/styles/main.css -w",
"build": "node scripts/build.js && postcss src/assets/styles/tailwind.css -o src/assets/styles/main.css"
}
index.js
import "./assets/styles/main.css";
// ...
I tried to create a component like this and its work
<div className="w-64 h-64 bg-red-200">hai</div>
but when I build, even I have given a path to purge at the config, the size not decreasing. It constant 143kb whether I add the purge path or not. i also have tried manual purge like this at postcss.config.js but no work
// postcss.config.js
const purgecss = require("#fullhuman/postcss-purgecss")({
// Specify the paths to all of the template files in your project
content: [
"./src/**/*.js"
// etc.
],
// This is the function used to extract class names from your templates
defaultExtractor: (content) => {
// Capture as liberally as possible, including things like `h-(screen-1.5)`
const broadMatches = content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || [];
// Capture classes within other delimiters like .block(class="w-1/2") in Pug
const innerMatches = content.match(/[^<>"'`\s.()]*[^<>"'`\s.():]/g) || [];
return broadMatches.concat(innerMatches);
}
});
module.exports = {
plugins: [
require("tailwindcss"),
require("autoprefixer"),
...(process.env.NODE_ENV === "production" ? [purgecss] : [])
]
};
whats wrong with my setup?

With the latest versions, starting at 1.4.0, you don't need to manually configure PurgeCSS.
// postcss.config.js
module.exports = {
plugins: [
require('tailwindcss'),
require('autoprefixer')
]
}
//tailwind.config.js
module.exports = {
purge: [
'./src/**/*.js'
],
theme: {
extend: {},
},
variants: {},
plugins: [],
}
// package.json
"scripts": {
"start": "npm run build:css && react-scripts start",
"build": "NODE_ENV=production npm run build:css && react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"build:css": "postcss tailwind.css -o src/main.css"
},
Note the NODE_ENV=production.
The documentation says:
Now whenever you compile your CSS with NODE_ENV set to production, Tailwind will automatically purge unused styles from your CSS.

I also have the same problem. This helped me:
https://tailwindcss.com/docs/optimizing-for-production#enabling-manually
I have to manually add this code in my tailwind.config.js file:
// tailwind.config.js
module.exports = {
purge: {
enabled: true,
content: ['./src/**/*.html'],
},
// ...
}
I hope it will be helpful.

Related

React app on Vercel - 404 not found error after adding Web Worker

I have my React app deployed to Vercel, and it was working until I added a web worker and a background task.
The app still builds and deploys with no error, but when I visit the url I get a 404 not found error.
It still runs fine locally as well.
I'm assuming it's the way I've set up the web worker using React-App-Rewired.
I use Rewired to avoid 'ejecting' my app, and it had me create a config-overrides.js (which I think is to override defaults in Webpack)
config-override.js
module.exports = function override(config, env) {
config.module.rules.push({
test: /\.worker\.js$/,
use: { loader: 'worker-loader' },
})
return config;
}
I think the problem is that Vercel is not finding the file paths correctly.
I tried a few approaches to fix this that I found here: https://github.com/webpack-contrib/worker-loader/issues/176
Like adding this line before returning config:
config.output.globalObject = '(self || this)'
It looks like people who use Next.js have had a similar problem and they fixed it like this:
module.exports = {
webpack: config => {
config.module.rules.push({
test: /\.worker\.js$/,
loader: 'worker-loader',
options: {
name: 'static/[hash].worker.js',
publicPath: '/_next/'
}
})
config.output.globalObject = `(typeof self !== 'undefined' ? self : this)`
return config
}
}
But I'm not using Next.
package.json scripts.
"scripts": {
"predeploy": "npm run build",
"deploy": "gh-pages -d build",
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom-fourteen",
"eject": "react-scripts eject"
},
An image so you can see my file structure (again it was working locally so I think everything is setup ok)
And here is the tutorial I followed to get set up with React-App-Rewired and web workers: https://medium.com/#danilog1905/how-to-use-web-workers-with-react-create-app-and-not-ejecting-in-the-attempt-3718d2a1166b
Any help is appreciated. Thanks!!
I needed to add this line right above the first line of my worker function
/* eslint-disable-next-line no-restricted-globals */
let mytimer;
/* eslint-disable-next-line no-restricted-globals */
self.onmessage = function(evt) {
clearInterval(mytimer);
if(evt.data.message === 'pause' || evt.data.message === 'stop' || evt.data.message === 'skip'){
postMessage(evt.data.time)
}
if (evt.data.message == "start" || evt.data.message == "break") {
var i = evt.data.time;
mytimer = setInterval(function() {
i--;
postMessage(i);
}, 1000);
}
};
And also have this in my config-overrides.js
config.output.globalObject = 'this';
module.exports = function override(config, env) {
config.module.rules.push({
test: /\.worker\.js$/,
use: { loader: 'worker-loader' },
})
config.output.globalObject = 'this';
return config;
}

Building a React-Electron app using electron-builder, index.js loads inside pre tags

I have an app that I'm now trying to build to distribute for testing.
I'm using React and Electron with electron-builder to build the app itself. I'm not a web developer so I've been trying to keep things basic and just get something to work.
After about five hours I was finally able to get the app to build somewhat properly and launch, but when it loads index.js (the first page in the app) it displays the source for index.js instead of rendering the content. In the devtools everything is inside a pre tag.
I've already looked at this thread and tried that but it didn't change anything, and I'm not using service workers as far as I can tell.
What the actual Electron window displays after launching with the devtools alongside.
Here's the createWindow function from main.js.
I've tried doing all kinds of things to the pathname with no effect.
function createWindow() {
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../src/index.js'),
protocol: 'file:',
slashes: true,
});
mainWindow = new BrowserWindow({
width: 800, height: 600, title: "Electron App", webPreferences: {
nodeIntegration: true
}
});
mainWindow.loadURL(startUrl);
mainWindow.on('closed', function () {
mainWindow = null;
});
}
Here are my scripts from package.json
"scripts": {
"start": "nf start -p 3000",
"start-electron": "set ELECTRON_START_URL=http://localhost:3000 && electron .",
"react-start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject",
"build-electron": "npm run build && electron-builder build --win"
}
Here's the build part too. To be honest, I don't really understand what this is or does but after a few hours of trial and error this is what gets me to the point I am now.
"build": {
"appId": "Test",
"extends": null,
"files": [
"./build/**/*",
"./electron/main.js",
"./src/**/*"
]
}
As far as I can tell, it has something to do with the Electron start URL, because when I removed that from const startUrl in createWindow, running the app using npm start did the same thing as the built Electron app, whereas before using npm would launch the app normally every time.
EDIT after solution:
Modified build in package.json to
"build": {
"appId": "Test",
"extends": null,
"files": [
"./build/**/*",
"./electron/main.js",
"./src/**/*"
],
"directories": {
"buildResources": "./public"
}
}
I haven't tested it without this modification so I'm not sure that it's actually necessary.
Start URL was changed to
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../build/index.html'),
protocol: 'file:',
slashes: true,
});
You're supposed to set it up with an html file.
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, '../src/index.html'),
protocol: 'file:',
slashes: true,
});
Your browser window should load the build/index.html on production mode
const isDev = require("electron-is-dev");
if (isDev) {
mainWindow.loadURL(process.env.ELECTRON_START_URL);
} else {
mainWindow.loadFile(path.join("build", "index.html"));
}

How to compress file size in tailwind using postcss?

I have the following postcss.config.js file:
// postcss.config.js
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
]
}
and the following tailwind.config.js file:
// tailwind.config.js
module.exports = {
purge: [
'./src/cljs/foo/*.cljs',
'./target/cljs-runtime/*.js',
'./target/cljsbuild/public/js/*',
'./target/cljsbuild/public/js/cljs-runtime/*',
'./target/*'
],
theme: {},
variants: {},
plugins: [],
}
And my goal is to compress the css generated, for which I've added the purge key in tailwind.config.js.
To generate the css from the .src tailwind file, styles.src.css:
#tailwind base;
#tailwind components;
#tailwind utilities;
I'm running the command:
postcss ./resources/public/css/styles.src.css -o ./resources/public/css/styles.css
from the root directory of my project that contains both the tailwind.config.js and the postcss.config.js. Yet after running the command, the generated css is 1.2MB, as big as what I had without the purge key. Why isn't postcss purge working?
You don't need that command with postcss.
Just add enabled:true in purge in tailwind.config.json and wrap your path into list as stated in https://tailwindcss.com/docs/optimizing-for-production#enabling-manually:
purge: {
enabled: true,
content: [
'./src/cljs/foo/*.cljs',
'./target/cljs-runtime/*.js',
'./target/cljsbuild/public/js/*',
'./target/cljsbuild/public/js/cljs-runtime/*',
'./target/*'
],
},
There it is! Now you can run and see the results:
npm run build:css
That's the command I use in package.json:
"scripts": {
"build:css": "tailwind build static/css/tw.css -o static/css/tailwind.css"
},
Your PostCSS configuration is split between tailwind.config.js and postcss.config.js, when it should all be in postcss.config.js.
Why?
Tailwind uses PostCSS behind the scenes. But PostCSS itself doesn't know about your tailwind.config.js file. To use the postcss command, you need to specify the purge option in the postcss.config.js file, not tailwind.config.js. This page on the Tailwind website explains the difference between the two files in detail.
Here is my setup:
// postcss.config.js
module.exports = {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
require('#fullhuman/postcss-purgecss')({
// Specify the paths to all of the template files in your project
content: [
'./src/cljs/foo/*.cljs',
'./target/cljs-runtime/*.js',
'./target/cljsbuild/public/js/*',
'./target/cljsbuild/public/js/cljs-runtime/*',
'./target/*'
],
// This extractor will tell PurgeCSS to ignore all CSS selectors and tags used in your files
defaultExtractor: content => Array.from(content.matchAll(/:?([A-Za-z0-9-_:]+)/g)).map(x => x[1]) || []
}),
]
}
Note my tailwind.config.js file is empty:
// tailwind.config.js
module.exports = {
purge: [],
theme: {
extend: {},
},
variants: {},
plugins: [],
}
Well you can also add purge key in postcss.config.js.
This is my config in
postcss.config.js
const purgecss = require('#fullhuman/postcss-purgecss')({
// Specify the paths to all of the template files in your project
content: ['./src/**/*.js', './public/index.html'],
// make sure css reset isnt removed on html and body
whitelist: ['html', 'body'],
// Include any special characters you're using in this regular expression
defaultExtractor: (content) => content.match(/[A-Za-z0-9-_:/]+/g) || [],
})
module.exports = {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
...(process.env.NODE_ENV === 'production' ? [purgecss] : []),
],
}
Important: The environment variable NODE_ENV is responsible for dev and prod environment. If you are using tailwindcss in dev mode, then you don't want to purge as you want to use all the available styles. By setting it for production mode will inform postcss and thus this will purge unused css.
Please take note that I haven't set any config for tailwindcss in webpack config.
At build time, make sure that you have your NODE_ENV set to specific value for production use case. You can use either 'production' or 'prod' doesn't matter. Same will reflect in postcss.config.js.
Tailwind will purge automatically - from their docs:
Now whenever you compile your CSS with NODE_ENV set to production, Tailwind will automatically purge unused styles from your CSS
https://tailwindcss.com/docs/controlling-file-size#basic-usage
You can run commands for your dev and production environments - development will keep all Tailwind's classes, production will run the purge.
package.json:
"dependencies": {
"autoprefixer": "^9.8.5",
"postcss-cli": "^7.1.1",
"tailwindcss": "^1.5.2"
},
"devDependencies": {
"cross-env": "^7.0.2"
},
"scripts": {
"watch": "cross-env NODE_ENV=development postcss static/css/tailwind.css -o style.css --watch",
"build": "cross-env NODE_ENV=production postcss static/css/tailwind.css -o style.css"
},
postcss.config.js
module.exports = {
plugins: [
require('tailwindcss'),
require('autoprefixer'),
]
}

React Dev Tools Thinks My Site is in Dev Mode

I want to see how much of a speed boost I get from using the non dev version of everything so I built my site using my "production" webconfig. but dev tools still is telling me it is in "development" mode
This page is using the development build of React.
const merge = require("webpack-merge");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const common = require("./webpack.common.js");
module.exports = merge(common, {
// Provides process.env.NODE_ENV with value production.
// Enables FlagDependencyUsagePlugin, FlagIncludedChunksPlugin,
// ModuleConcatenationPlugin, NoEmitOnErrorsPlugin, OccurrenceOrderPlugin,
// SideEffectsFlagPlugin and UglifyJsPlugin.
mode: "production",
// see https://webpack.js.org/configuration/optimization/
optimization: {
// minimize default is true
minimizer: [
// Optimize/minimize CSS assets.
// Solves extract-text-webpack-plugin CSS duplication problem
// By default it uses cssnano but a custom CSS processor can be specified
new OptimizeCSSAssetsPlugin({})
]
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
// only use MiniCssExtractPlugin in production and without style-loader
use: [MiniCssExtractPlugin.loader, "css-loader", "sass-loader"]
}
]
},
plugins: [
// Mini CSS Extract plugin extracts CSS into separate files.
// It creates a CSS file per JS file which contains CSS.
// It supports On-Demand-Loading of CSS and SourceMaps.
// It requires webpack 4 to work.
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
}),
new BundleAnalyzerPlugin()
]
});
in my package.json
"scripts": {
"dev": "cross-env NODE_ENV=dev webpack-serve --config webpack.dev.js --open",
"prod": "cross-env NODE_ENV=prod webpack -p --config webpack.prod.js",
"qa": "cross-env NODE_ENV=QA webpack --config webpack.prod.js"
},
My confidence is growing that your problem stems from setting NODE_ENV to prod in your package.json. I think you should instead set it to production, or allow webpack to set it internally with the mode option in your webpack config.
The react-scripts package explicitly sets this value to production for building and searching for NODE_ENV in the facebook/react project in github project shows tons of checks for production as the value instead of prod.
Here's the index.js file for react-is, many other projects in the react source follow the same pattern:
'use strict';
if (process.env.NODE_ENV === 'production') {
module.exports = require('./cjs/react-is.production.min.js');
} else {
module.exports = require('./cjs/react-is.development.js');
}
I would try changing your build script to:
"prod": "cross-env NODE_ENV=production webpack -p --config webpack.prod.js",
or even let webpack -p set it automatically:
"prod": "cross-env webpack -p --config webpack.prod.js",

Error: Cannot export when target is not server. with next js and zeit-NOW during deployee

I am working a react app where i am using next js and express, I have choose zeit now for servless but when i deploying this facing error Error: No serverless pages were built
next.config.js
const configuration = withTypescript(
withLess({,
target: process.env.NODE_ENV === "development" ? "server" : "serverless",
cssModules: true,
lessLoaderOptions: {
javascriptEnabled: true,
modifyVars: themeVariables // make your antd custom effective
},
exportPathMap: async function(defaultPathMap) {
return {
"/": { page: "/index" },
};
},
webpack: config => {
config.plugins = config.plugins || [];
config.plugins = [
...config.plugins,
// Read the .env file
new Dotenv({
path: path.join(__dirname, "../.env"),
systemvars: true
})
];
return config;
},
})
);
module.exports = configuration;
using next version : "#types/next": "^8.0.0",
now.json
{
"version": 2,
"name": "web",
"builds": [
{ "src": "package.json", "use": "#now/next" }
],
}
inside package json
"scripts": {
"dev": "next src",
"build": "next build src",
"start": "next run build && next start src",
"export": "npm run build && next export src -o ./out",
"now-build": "next build src","
},
Getting error from zeit Now logs
preparing lambda files...
2019-04-19T17:24:04.955Z Error: No serverless pages were built. https://err.sh/zeit/now-builders/now-next-no-serverless-pages-built
at Object.exports.build (/tmp/utils/build-module/node_modules/#now/next/index.js:305:13)
at <anonymous>
please help me here to figure it out.
Thanks.

Resources