I'm very new to using Node.js and using post processors for CSS. After reading several articles, I managed to install the following:
Node.js (which included npm)
Gulp
PostCSS
Pxtorem (a PostCSS plugin for Gulp)
What I would like to do is have the 'pxtorem' plugin convert my px units to rems for the following CSS properties: font-size, margin, padding, border, width, height etc. and out output the results in a new CSS stylesheet.
Question: What exactly do I need to have typed inside my gulpfile.js to make this work?
To reiterate, I'm brand new when it comes to typing variables and requirements and have been following video and blog examples, none of which specifically have the correct formula for converting pixels to rems (since there are many plugins for PostCSS).
This is what I currently have in my current gulpfile.js:
var gulp = require('gulp');
var postcss = require('gulp-postcss');
var pxtorem = require('gulp-pxtorem');
gulp.task('css', function() {
gulp.src('./css-1/*.css')
.pipe(pxtorem())
.pipe(gulp.dest('./dest'));
});
What the above is essentially doing is grabbing my "styles-1.css" stylesheet file located within my "css-1" folder and making a duplicate of it inside my "dest" folder. I typed this code in compliance with an article I was reading to get an idea of how PostCSS worked, but it obviously isn't the correct code for converting pixels to rem.
P.S. I'm currently using a Windows 10 O/S.
Based on the documentation for gulp-pxtorem, it states:
Options
Pass in two option objects. The first one for postcss-pxtorem
options...
After visiting the documentation for postcss-pxtorem, I found that the options block looks like this:
{
rootValue: 16,
unitPrecision: 5,
propWhiteList: ['font', 'font-size', 'line-height', 'letter-spacing'],
selectorBlackList: [],
replace: true,
mediaQuery: false,
minPixelValue: 0
}
Which is pretty self explanatory, but you can read more in the docs if you need to know what every option does. The option you want is propWhiteList.
So, in your gulpfile:
var gulp = require('gulp');
var postcss = require('gulp-postcss');
var pxtorem = require('gulp-pxtorem');
gulp.task('css', function() {
var opts = {
propWhiteList: [
'font-size',
'margin',
'padding',
'border',
'width',
'height',
...etc
]
};
gulp.src('./css-1/*.css')
.pipe(pxtorem(opts))
.pipe(gulp.dest('./dest'));
});
I don't believe you need to use the second option to achieve your desired result.
Good luck, and happy coding!
Related
I am working on building small applications that will live in a website. The website that will host these applications may or may not be using a css framework. I Want to prefix all Bootstrap classes with my own unique prefix.
To avoid "ANY INSTANCE or CHANCE" of conflict I want to prefix all Bootstrap CSS classes with - let's say - "year19-" prefix. So, for example, all the col- classes would now be year19-col- and all the .btn classes would now become .year19-btn, .year19-btn-primary, etc...
I know if I use the sass theme, new classes, then we would get around some of that as we can create our own prefixes using the theming approach, but JS would still remain a source of conflict if two versions of the same framework live on the same page. There was a Github project for Bootstrap 3 with the namespacing feature where you could just add your prefix in the namespace variable then compile the entire code to a CSS and JS package. Bootstrap 4 doesn't seem to have that package yet.
Also, I don't want to wrap the project with a css class. That approach is fine for some things, but not the right approach. I wouldn't even call that namespace. That is just wrapping the classes.
year19-btn-primary {
then this would be whatever the code that already existed there before, not touched.}
I managed to get classes prefixed for Bootstrap 5.1.3. You'll need to make the following changes before compiling Bootstrap yourself. My full implementation is available here: https://github.com/Robpol86/sphinx-carousel/tree/85422a6d955024f5a39049c7c3a0271e1ee43ae4/bootstrap
package.json
"dependencies": {
"bootstrap": "5.1.3",
"postcss-prefix-selector": "1.15.0"
},
Here you'll want to add postcss-prefix-selector to make use of it in postcss.
postcss.config.js
'use strict'
const prefixer = require('postcss-prefix-selector')
const autoprefixer = require('autoprefixer')
const rtlcss = require('rtlcss')
module.exports = ctx => {
return {
map: ctx.file.dirname.includes('examples') ?
false :
{
inline: false,
annotation: true,
sourcesContent: true
},
plugins: [
prefixer({
prefix: 'scbs-', // ***REPLACE scbs- WITH YOUR PREFIX***
transform: function (prefix, selector) {
let newSelector = ''
for (let part of selector.split(/(?=[.])/g)) {
if (part.startsWith('.')) part = '.' + prefix + part.substring(1)
newSelector += part
}
return newSelector
},
}),
autoprefixer({
cascade: false
}),
ctx.env === 'RTL' ? rtlcss() : false,
]
}
}
This is where the CSS will be prefixed. I'm using postcss instead of just wrapping bootstrap.scss with a class/id selector so I can use the Bootstrap 5 carousel component on Bootstrap 4 webpages (which is my use case). This will replace https://github.com/twbs/bootstrap/blob/v5.1.3/build/postcss.config.js
rollup.config.js
// ...
const plugins = [
replace({ // ***COPY/PASTE FOR OTHER BOOTSTRAP COMPONENTS***
include: ['js/src/carousel.js'], // ***YOU MAY NEED TO REPLACE THIS PATH***
preventAssignment: true,
values: {
'CLASS_NAME_CAROUSEL': '"scbs-carousel"', // ***USE YOUR PREFIXES HERE***
'CLASS_NAME_ACTIVE': '"scbs-active"',
'CLASS_NAME_SLIDE': '"scbs-slide"',
'CLASS_NAME_END': '"scbs-carousel-item-end"',
'CLASS_NAME_START': '"scbs-carousel-item-start"',
'CLASS_NAME_NEXT': '"scbs-carousel-item-next"',
'CLASS_NAME_PREV': '"scbs-carousel-item-prev"',
'CLASS_NAME_POINTER_EVENT': '"scbs-pointer-event"',
'SELECTOR_ACTIVE': '".scbs-active"',
'SELECTOR_ACTIVE_ITEM': '".scbs-active.scbs-carousel-item"',
'SELECTOR_ITEM': '".scbs-carousel-item"',
'SELECTOR_ITEM_IMG': '".scbs-carousel-item img"',
'SELECTOR_NEXT_PREV': '".scbs-carousel-item-next, .scbs-carousel-item-prev"',
'SELECTOR_INDICATORS': '".scbs-carousel-indicators"',
}
}),
babel({
// Only transpile our source code
// ...
Lastly rollup replace plugin is used to add the prefixes in the compiled javascript file. I wasn't able to find a way to just prefix the consts so I had to resort to having the entire const replaced and hard-coded with the full class names. This means you'll need to do this for every Bootstrap component that you're including in your final build (for me I just need the carousel so it's not a big deal).
I have a django blog project, which is up and running on a live server.
I am using the TailwindCSS framework, and as part of that I have followed the extensive tutorial on setting up Gulp. I am experimenting with responsive design, but when I add eg:
<div style="flex-wrap justify-end w-full p-6 m-auto border md:bg-blue sm:bg-yellow lg:bg-black>
Only one (sometimes two, but not all three) of the responsive bg elements actually works when I alter the window in Chrome Dev Tools. I have tried clearing my browser cache as I know this sometimes causes problems. This got me thinking that my setup isn't right, and then I realised my understanding of gulp needs to improve.
I have the root static folder as the collection point for my gulp outputs and collectstatic, and the structure of my project is as follows:
nomadpad-
-static
-css
-styles.css
-custom.css
-posts (app)
-static
-css
-styles.css
-custom.css
-src
-css
-styles.css (default tailwind config file)
- ...
.gulpfile:
//Include Gulp
var gulp = require('gulp');
var connect = require('gulp-connect');
var postcss = require('gulp-postcss');
var pug = require('gulp-pug');
var autoprefixer = require('autoprefixer');
//Define base folders
var src = '/src/';
var dest = '/static/';
var posts = '/posts/static/';
// Include plugins
var plugins = require("gulp-load-plugins")({
pattern: ['gulp-*', 'gulp.*', 'main-bower-files'],
replaceString: /\bgulp[\-.]/
});
// Concatenate & Minify JS
gulp.task('scripts', function() {
var jsFiles = [posts + 'js/*'];
//plugins.mainBowerFiles() returns an array of all the main
//files from the packages and
//plugins.filter('*.js') uses gulp-filter to pass only JS files.
gulp.src(plugins.mainBowerFiles().concat(jsFiles))
.pipe(plugins.filter('*.js'))
.pipe(plugins.concat('main.js'))
.pipe(plugins.uglify())
.pipe(gulp.dest(dest + 'js'));
});
//Compile CSS
gulp.task('css', function() {
var cssFiles = [posts +'css/*'];
gulp.src(plugins.mainBowerFiles().concat(cssFiles))
.pipe(plugins.filter('*.css'))
.pipe(plugins.concat('main.css'))
.pipe(plugins.uglify())
.pipe(gulp.dest(dest + 'css'));
});
// Compile tailwind
gulp.task('tailwind', function () {
var postcss = require('gulp-postcss');
var tailwindcss = require('tailwindcss');
return gulp.src(posts + 'css/*')
.pipe(postcss([
tailwindcss('tailwind.js'),
require('autoprefixer'),
]))
.pipe(gulp.dest(dest + 'css/*'))
.pipe(connect.reload())
});
gulp.task('html', function() {
gulp.src('./templates/posts/*.html')
.pipe(pug())
.pipe(gulp.dest(dest + 'html'))
});
// Watch for changes in files
gulp.task('watch', function() {
gulp.watch(dest + 'css/*', ['css']);
gulp.watch(dest + 'html/*', ['html']);
gulp.watch(dest + 'js/*', ['scripts']);
});
gulp.task('connect', function() {
connect.server({
root: 'build',
livereload: true,
open: true
});
});
// Default Task
gulp.task('default', ['css', 'tailwind', 'html', 'scripts']);
gulp.task('start', ['connect', 'watch']);
I appreciate the layout of this file and my structure is a little messy.
Without calling "gulp" in the command line, my Tailwind styles mostly work fine. My questions are:
When I call gulp, why is there no output in my static folders? What changes need to be made to ensure this works? Eg: My django templates should be being pulled through the html pipe.
When I call collectstatic, this updates the css files in /static (hence the two CSS files in the root static. What is the difference between using gulp and collectstatic, and how do I use them together?
At what point should I be using gulp and gulp start? I feel like I have put a lot of effort in to implementing this, but it is just wasted on me :-(
Are the issues I'm having with TailwindCSS responsive attributes related to my gulp set-up or lack of usage of gulp?
Many thanks,
David
i hope you solved this incase u did not i would recommend you use this package to easily integrate tailwind css with Django check it out here https://github.com/timonweb/django-tailwind
var paths = {
css: './public/apps/user/**/*.css'
}
var dest = {
css: './public/apps/user/css/'
}
// Minify and concat all css files
gulp.task('css', function(){
return gulp.src(paths.css)
.pipe(concatCSS('style.css'))
.pipe(minifyCSS({keepSpecialComments: 1}))
.pipe(rename({
suffix: '.min'
}))
.pipe(gulp.dest(dest.css))
});
When I first run the task it compiles alright and all changes are there.
After I change something and run it again it doesn't overwrite the existing minified css file. If I were to delete the minified css and run task again everything works perfect. Any insights?
Try and set the exact path, not a variable. Not that its not a good practice, just try without it.
Also , add a 'use strict'; to your task, so that you can be sure there are no serious errors with your settings. It will give you the right type of errors if there are any.
And, may I ask why are you concatenating your CSS before the production build?
Every file concatenation, minification and etc. should be performed in the 'build' task.
You have to delete your minified version of css before doing minify css.
To achieve this you can use gulp-clean
install gulp-clean as npm install gulp-clean
var gulp = require('gulp'),
concat = require('gulp-concat'),
cleanCSS = require('gulp-clean-css'), // this is to minify css
clean = require('gulp-clean'), //this is to delete files
gulp.task('del-custom-css', function(){
return gulp.src('./static/custom/css/custom.min.css',{force: true})
.pipe(clean())
});
gulp.task('minify-custom-css', ['del-custom-css'], function(){
return gulp.src(['./static/custom/css/*.css'])
.pipe(concat('custom.min.css'))
.pipe(cleanCSS())
.pipe(gulp.dest('./static/custom/css'))
});
Hope it helps.
I use gulp to compile my sass file to css files, and reference the css file in my html. The project support theme switch. For example, I have 3 css theme files:
red.css
yellow.css
blue.css
I can currently switch the theme css like this:
var styleDom = $('#theme-style');
var newHref = 'styles/themes/' + themeName + '.css';
if (styleDom.attr('href') !== newHref) {
styleDom.attr('href', newHref);
}
Now I want to use webpack to load the css file.
require('styles/themes/red.css');
It seems work well, but I cannot find a way to switch the theme css file now, does anyone have a solution?
Your approach doesn’t need to change. Just use Extract Text plugin to save out the CSS files. You’ll need to make multiple entry points to create multiple CSS files.
OR
More ideally, (the approach I would take) make your CSS switch based on a different html or body class and just change the class. It won’t add much overhead, and it will be a more ideal UX when changing themes.
You'll need to use a combination of webpacks style-loader and file-loader (second example ) and use require.ensure (second example "dynamic imports") to accomplish this:
function switchTheme(name) {
// Remove the current theme stylesheet
// Note: it is important that your theme css always is the last
// <link/> tag within the <head/>
$('head link[rel="stylesheet"]').last().remove();
// Since webpack needs all filePaths at build-time
// you can't dynamically build the filePath
switch(name) {
case 'red':
// With require.ensure, it is possible to tell webpack
// to only load the module (css) when require is actually called
return require.ensure([], function () {
require('style-loader/url!file-loader!styles/themes/red.css');
});
case 'yellow':
return require.ensure([], function () {
require('style-loader/url!file-loader!styles/themes/yellow.css');
});
case 'blue':
return require.ensure([], function () {
require('style-loader/url!file-loader!styles/themes/blue.css');
});
default:
throw new Error('Unknown theme "' + name + '"');
}
}
Then a call like switchTheme('blue') should do the trick.
And you might have to check your current webpack.config.js, in case you already have configured a loader for .css files.
I am attempting to make the switch from GruntJS to Gulp and have run into a problem with my Gulp task for processing my SASS files via Compass. The files compile just fine into the single CSS file as they did under my GruntJS implementation, but I am missing the line number comments that show me where the CSS rules come from such as:
/* line 26, ../_components/sass/_base.scss */
The code from my gulpfile.js for the task is:
gulp.task('compass', function() {
gulp.src(sassSources)
.pipe(compass({
comments: true,
sass: '_components/sass',
image: 'builds/dev/images',
style: 'nested'
})
.on('error', gutil.log))
.pipe(gulp.dest('builds/dev/css'))
});
Am I missing something?
Be careful with gulp-compass, it is not a gulp plugin (albeit named so) and has been blacklisted by the Gulp community for quite a while. It does not what Gulp plugins are supposed to do (e.g. it's possible to run them without gulp.src and gulp.dest), and other plugins are already doing its work perfectly fine. One of those plugins is gulp-ruby-sass. This setup might work for you:
var sass = require('gulp-ruby-sass');
gulp.task('compass', function() {
return sass(sassSources, {
compass: true,
lineNumbers: true
}).on('error', gutil.log))
.pipe(gulp.dest('builds/dev/css'))
});
This uses gulp-ruby-sass which is able to run with the compass extension. You see that I activated lineNumbers here to give you said output.
I see from your Gulpfile that you might have some extension requiring some images, I don't know exactly what that does, but if it's mandatory to your setup, you might better call compass directly (the command line tool) using require('child_process').exec(...)
You should add sass_options = { :line_numbers => true } to your config.rb file even if gulp-compass module doesn't support lineNumbers as an option.
important part of config.rb file
css_dir = 'app/assets/style/'
sass_dir = 'app/assets/style/sass/'
images_dir = 'app/assets/image/'
javascripts_dir = 'app/assets/script/'
sass_options = { :line_numbers => true }
And your gulp task should look like this
important part of gulpfile.js file
return gulp.src('./app/assets/style/sass/*.scss')
.pipe(plugins.compass({
config_file: './config.rb', // if you don't use a config file , you should start using immediately
css: './app/assets/style/',
sass: './app/assets/style/sass/',
image: './app/assets/image/',
line_comments: true,
sourcemap: true
}))
.pipe(gulp.dest('./app/assets/style/'));
I had trouble generating the line number comments using gulp-compass also. I tried a lot of things including matching all the plugin versions to the sample code I used to even completely discarding my code and use the full sample instead to no avail.
On top of its lack of compliance with gulp standards as #ddprrt suggested, gulp-compass seems to be broken now. Besides generating a stylesheet on the destination folder, it also generates another under the {app_root}/css folder. I suspect, the latter is some sort of caching, but that functionality is currently broken. As can be seen here, if you delete that stylesheet and re-run the task, the line number comments will finally show up. Below, I automated this by installing and using the gulp-clean-dest plugin. I have no tried using other plugins, but this hack handles the issue.
var gulp = require("gulp")
, compass = require("gulp-compass")
, cleanDest = require("gulp-clean-dest")
;
gulp.task("compass", function() {
gulp.src("components/sass/style.scss")
.pipe(compass(
{ "sass": "components/sass"
, "image": "builds/development/images"
, "style": "expanded"
, "comments": true
})
.on("error", gutil.log)
)
.pipe(gulp.dest("builds/development/css"))
.pipe(cleanDest("css"))
});