How to use PostCSS autoprefixer through PostCSS-cli? - postcss

I came across the PostCSS autoprefixer docs,
I didn't get what arguments to pass with.
Input File path --use use autoprefixer -d Output CSS path
npx postcss ./assets/styles.css -- use autoprefixer -d build
The docs didn't make sense.
module.exports = {
"plugins" : [
require('autoprefixer')({
browsers: ['> 1%', 'last 4 versions'],
}),
require('postcss-import'),
require('postcss-partial-import')({
prefix: '_'
}),
require('postcss-nested'),
require('postcss-each'),
require('postcss-each-variables'),
require('postcss-for'),
require('postcss-custom-media'),
require('postcss-at-rules-variables'),
require('cssnano')({
preset: ['default', {
discardComments: {
removeAll: true,
},
}]
}),
require('cssnano-preset-advanced'),
require('#fullhuman/postcss-purgecss')({
content: ['./**/*.html']
}),
]
}

Related

Local #import does not result in text substitution

I've followed this video and chrissainty/ondotnet-tailwindcss to configure Tailwind with the JIT and I'm pretty happy!
However, I wanted to take advantage of postcss-import to include multiple css files. Here's what my app.css looks like:
#import "tailwindcss/base";
#import "tailwindcss/components";
#import "tailwindcss/utilities";
#import "./other.css";
However, in the generated css I see generated code for Tailwind, but not for my other.css - it's still #import "./other.css". Here's my folder structure:
./Styles/app.css
./Styles/other.css
./package.json
./postcss.config.js
./tailwind.config.js
This is my postcss command:
cross-env TAILWIND_MODE=build postcss ./Styles/app.css -o ./wwwroot/css/app.css
I'm assuming that the problem is something to do with the Current Working Directory? I've tried the following variants for my #import statement:
#import ./Styles/other.css
#import ../Styles/other.css
#import Styles/other.css
But the text substitution doesn't happen. I've tried this with and without postcss-import in the devDependencies of the package.json.
I've included the contents of the config files, just in case.
package.json:
{
"scripts": {
"buildcss:dev": "cross-env TAILWIND_MODE=build postcss --verbose ./Styles/app.css -o ./wwwroot/css/app.css",
"buildcss:release": "cross-env NODE_ENV=production postcss ./Styles/app.css -o ./wwwroot/css/app.css"
},
"devDependencies": {
"autoprefixer": "10.3.1",
"cross-env": "7.0.3",
"cssnano": "^5.0.6",
"postcss": "8.3.6",
"postcss-cli": "8.3.1",
"postcss-import": "^14.0.2",
"tailwindcss": "2.2.7"
},
"dependencies": {
"#tailwindcss/forms": "^0.3.3"
}
}
postcss.config.js:
// postcss.config.js
const purgecss = require('#fullhuman/postcss-purgecss')({
// Specify the paths to all of the template files in your project
content: [
'./**/*.html',
'./**/*.razor'
],
// Include any special characters you're using in this regular expression
defaultExtractor: content => content.match(/[\w-/:]+(?<!:)/g) || []
})
// postcss.config.js
module.exports = {
plugins: [
require('postcss-import'),
require('tailwindcss'),
require('autoprefixer'),
...process.env.NODE_ENV === 'production'
? [purgecss]
: []
]
}
tailwind.config.js:
module.exports = {
mode: 'jit',
purge: [
'./**/*.razor',
'./**/*.cshtml'
],
darkMode: false, // or 'media' or 'class'
theme: {
extend: {
zIndex: {
'1': '1'
},
},
},
variants: {
extend: {
ringWidth: ['focus'],
borderWidth: ['focus'],
},
},
plugins: [
require('#tailwindcss/forms'),
],
}
Aha! It was the postcss config. I was looking at the wrong file. The original config was this:
module.exports = ({ env }) => ({
plugins: {
tailwindcss: {},
autoprefixer: {},
cssnano: env === "production" ? { preset: "default" } : false
}
});
It was missing the postcss-import plugin:
module.exports = ({ env }) => ({
plugins: {
tailwindcss: {},
autoprefixer: {},
'postcss-import': {},
cssnano: env === "production" ? { preset: "default" } : false
}
});

CommonJS rollup plugin syntax error when importing 3rd party libraries, mostly related to 'process'

I've been working on a custom rollup config which takes a React project, and inlines the js and css in index.html.
When I've imported some third party react libraries (like material-ui-color) I run into a problem with CommonJS where it says there's a syntax error. Of the libraries I've tried to install so far, the word 'process' is most commonly the word it breaks on. Here is the log from the material-ui-color issue:
[!] (plugin commonjs) SyntaxError: Unexpected token (205:28) in /Users/meyerm/Documents/GitHub/button-generator-figma-plugin/node_modules/jss/dist/jss.esm.js
node_modules/jss/dist/jss.esm.js (205:28)
203: var newValue = value;
204:
205: if (!options || options.process !== false) {
^
I've included the rollup-plugin-replace to fix any occurrences of process.env.NODE_ENV but this seems to be a different issue.
Here is my rollup config:
import resolve from '#rollup/plugin-node-resolve';
import commonjs from '#rollup/plugin-commonjs';
import babel from '#rollup/plugin-babel';
import livereload from 'rollup-plugin-livereload';
import replace from '#rollup/plugin-replace';
import { terser } from 'rollup-plugin-terser';
import postcss from 'rollup-plugin-postcss';
import html from 'rollup-plugin-bundle-html-plus';
import typescript from 'rollup-plugin-typescript';
import svgr from '#svgr/rollup';
const production = !process.env.ROLLUP_WATCH;
export default [
/*
Transpiling React code and injecting into index.html for Figma
*/
{
input: 'src/app/index.tsx',
output: {
name: 'ui',
file: 'dist/bundle.js',
format: 'umd',
},
plugins: [
// What extensions is rollup looking for
resolve({
extensions: ['.jsx', '.js', '.json', '.ts', '.tsx'],
}),
// Manage process.env
replace({
preventAssignment: true,
process: JSON.stringify({
env: {
isProd: production,
},
}),
'process.env.NODE_ENV': JSON.stringify(production),
}),
typescript({ sourceMap: !production }),
// Babel config to support React
babel({
presets: ['#babel/preset-react', '#babel/preset-env'],
babelHelpers: 'runtime',
plugins: ['#babel/plugin-transform-runtime'],
extensions: ['.js', '.ts', 'tsx', 'jsx'],
compact: true,
exclude: 'node_modules/**',
}),
commonjs({
include: 'node_modules/**',
}),
svgr(),
// Config to allow sass and css modules
postcss({
extensions: ['.css, .scss, .sass'],
modules: true,
use: ['sass'],
}),
// Injecting UI code into ui.html
html({
template: 'src/app/index.html',
dest: 'dist',
filename: 'index.html',
inline: true,
inject: 'body',
ignore: /code.js/,
}),
// If dev mode, serve and livereload
!production && serve(),
!production && livereload('dist'),
// If prod mode, minify
production && terser(),
],
watch: {
clearScreen: true,
},
},
/*
Main Figma plugin code
*/
{
input: 'src/plugin/controller.ts',
output: {
file: 'dist/code.js',
format: 'iife',
name: 'code',
},
plugins: [resolve(), typescript(), commonjs({ transformMixedEsModules: true }), production && terser()],
},
];
function serve() {
let started = false;
return {
writeBundle() {
if (!started) {
started = true;
// Start localhost dev server on port 5000 to work on the UI in the browser
require('child_process').spawn('npm', ['run', 'start', '--', '--dev'], {
stdio: ['ignore', 'inherit', 'inherit'],
shell: true,
});
}
},
};
}
Any ideas how I can overcome this and import 3rd party libraries into the project easily?
I recommend rewriting the config in the following way:
replace({
"process.env.isProd": production,
}),

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'),
]
}

How to load environment variables in React

I've been trying to load environment variables in React and I can't seem to figure it out. I have tried multiple aproaches:
Load them using the dotenv-webpack package
webpack.config.dev.js
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const template = require('html-webpack-template');
const Dotenv = require('dotenv-webpack');
const baseConfig = require('./webpack.config.base');
module.exports = merge(baseConfig, {
mode: 'production',
plugins: [
new HtmlWebpackPlugin({
template,
inject: false,
appMountId: 'app',
mobile: true,
lang: 'es-ES',
title: 'My App',
meta: [
{
name: 'description',
content: 'My App',
},
],
}),
new Dotenv(),
],
});
.env
API_HOST=http://localhost:8000
REACT_APP_API_HOST=http://localhost:8000
Passing it directly on the package.json script:
"start": "webpack-dev-server --config ./webpack.config.dev.js"
Using .env on the webpack command
webpack --env.API_HOST=http://localhost:8000
Using webpack.environmentPlugin
const webpack = require('webpack');
const merge = require('webpack-merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const template = require('html-webpack-template');
const baseConfig = require('./webpack.config.base');
module.exports = merge(baseConfig, {
mode: 'development',
devtool: 'cheap-module-source-map',
devServer: {
publicPath: '/',
contentBase: './dist',
compress: true,
stats: 'minimal',
overlay: true,
historyApiFallback: true,
port: 8081,
hot: true,
},
plugins: [
new HtmlWebpackPlugin({
template,
devServer: 'http://localhost:8081',
inject: false,
appMountId: 'app',
mobile: true,
lang: 'es-ES',
title: 'My App',
meta: [
{
name: 'description',
content: 'React template.',
},
],
}),
new webpack.EnvironmentPlugin({
API_HOST: 'http://localhost:8000',
}),
],
});
None of this approaches work and when I try to access process.env variables in my React code I get undefined
Any ideas of what I could be doing wrong?
I've been fighting with environment variables myself for some time, when I wanted to provide settings to the Firebase project but not load them into the public repository.
As far as I know, you need to name you environment variables should always start with the prefix REACT_APP_. You can define them whereever you like, but if you created your app with create-react-app tool then you can put your variables in .env file, or a few other files - (https://facebook.github.io/create-react-app/docs/adding-custom-environment-variables)
The pain for me started when I wanted to make my own files, because I had two different Firebase projects - one for staging and one for production.
I end up with using react-app-env module which helped with:
- defining my own files - staging.env and production.env
- auto prefix my variables with REACT_APP_
For example:
I have defined Firebase ApiKey in staging.env file:
API_KEY=xxxxxxxxxxxxxxxxxxx
when I use it in my firebase.js file, I use it as:
const config = {
apiKey: process.env.REACT_APP_API_KEY,
}
And to make sure that I develop against staging environment (Firebase project) I've changed my package.json to:
"scripts": {
"start": "react-app-env --env-file=staging.env start",
},
Hope that helps!
You need to specify the webpack config file correct. You will need to create a separate config for dev. (webpack.config.dev.js)
Example here.
scripts: {
"dev": "webpack --env.API_HOST=http://localhost:8000 --config webpack.config.dev.js"
}
Also, you need to use Webpack.DefinePlugin.
plugins: [
...
new webpack.DefinePlugin({ `process.env.API_HOST`: JSON.stringify(${env.API_HOST}) })
]
or you can use reduce to make it more comprehensive.
const envKeys = Object.keys(env).reduce((prev, next) => {
prev[`process.env.${next}`] = JSON.stringify(env[next]);
return prev;
}, {});
return {
plugins: [
...
new webpack.DefinePlugin(envKeys)
]
};
Agree with #Philip's answer, this is how I structure my dev.config.js
...
plugins: [
new webpack.DefinePlugin({
// process.env
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV),
WHY_DID_YOU_UPDATE: process.env.WHY_DID_YOU_UPDATE,
},
// my other global flags
__CLIENT__: true,
__SERVER__: false,
__DEVELOPMENT__: true,
__DEVTOOLS__: true
}),
]
I also use better-npm-run to manage my package.json, where you can easily manage the env variables
"betterScripts": {
"dev": {
"command": "concurrently --kill-others \"better-npm-run watch-client\" \"better-npm-run start-dev\" \"gulp watch --gulpfile semantic/gulpfile.js\""
},
"why-did-you-update": {
"command": "better-npm-run dev",
"env": {
"WHY_DID_YOU_UPDATE": true
}
},
"watch-client": {
"command": "node webpack/webpack-dev-server.js",
"env": {
"UV_THREADPOOL_SIZE": 100,
"NODE_ENV": "development",
"NODE_PATH": "./src",
"PORT": 3000
}
},
"build": {
"command": "webpack --verbose --colors --display-error-details --config webpack/prod.config.js"
}
},
Hope this information helps you too!
I find a simple solution for this. You need to install 'dotenv-webpack', then add this configuration to your webpack config:
const Dotenv = require('dotenv-webpack');
...
plugins: [
new Dotenv(),
],
...
.env
DB_HOST=127.0.0.1
DB_PASS=foobar
S3_API=mysecretkey
Finally you can access your env variables in your app
console.log(process.env.DB_PASS);
From the docs: the .env values for DB_HOST and S3_API are NOT present in our bundle, as they were never referenced (as process.env.[VAR_NAME]) in the code.
Hope it helps!
You can specify environment variables in the package.json scripts section:
{
...
"scripts": {
"start": NODE_ENV=development webpack-dev-server
},
...
}

Webpack v4, ejected create-react-app. How to configure autoprefixer?

I'm in a pickle.
I have used a create-react-app (v2), ejected it, and build my project structure along the lines of
projectDir > src > pages > page > page.js || page.css
and I have multiple pages.
I've been trying to configure webpack with postcss and autoprefixer, but there is nothing remotely resembling what I have for my webpack.config.dev.js. Here is the part of my webpack that has the postcss with autoprefixer:
const getStyleLoaders = (cssOptions, preProcessor) => {
const loaders = [
require.resolve('style-loader'),
{
loader: require.resolve('css-loader'),
options: cssOptions,
},
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
}),
],
},
},
];
if (preProcessor) {
loaders.push(require.resolve(preProcessor));
}
return loaders;
};
Its the base one after I eject the app.
Also, I added the postcss.config.js to my root directory but I don't know where to import it.
module.exports = {
plugins: [
require('autoprefixer')
],
};
Anyone has any tips on how to proceed to make autoprefixer work with this?
CRA uses autoprefixer out of the box

Resources