Bootstrap - Sass - Gulp - Toolchain

[color="#006400"][b]/*******************************************

The following discussion leads to a complete Gulp, Sass and Yii asset workflow

with the result that only one JS and one CSS is produced.

The code that is referenced throughout the discussion is the source code

for yiiframework.com.

It can be found here: https://github.com/y...iiframework.com

******************************************/

[/b][/color]

[color="#8B0000"][b]/*******************************************

[/b]Yii application templates based on Gulp and Sass available:

[/color]BOOTSTRAP:

Basic: yii2-app-basic-gulp-sass

Advanced: yii2-app-advanced-gulp-sass

FOUNDATION:

Basic: yii2-app-basic-zurbified

Advanced: yii2-app-advanced-zurbified

[color="#8B0000"][b]******************************************/

[/b][/color]

Hi,

I’ve been trying all day trying to figure this one out but I am at a loss.

I have moved a copy of the @vendor/bower/bootstrap folder into /frontend/assets and overridden the bootstrap bundles configuration in the frontend config to reflect this.

I am looking to customise the bootstrap files in order to 1) remove unneeded CSS and 2) change the remaining CSS to reflect the desired styling of my frontend.

What I just don’t seem to be able to figure out is how to do this either intrinsically with yii, through a Yii extension or via a solution external to the Yii application.

I previously had recompiling working on a previous project when using a plugin for PHPStorm but this does not seem to work anymore.

Is there a way to recompile Bootstrap in Yii using the .less files?

As always, any and all advice greatly appreciated :)

1 Like

Bootstrap 4 will be out any day now, and it is now based on Sass.

So, my advice is to grab the Sass package for Bootstrap 3.x - you can get it from the Bootstrap site.

And set up a tool-chain separate from Yii.

Using PHP for this is in my opinion a very bad idea.

We are using Node.js and Gulp for our build script at https://github.com/yiisoft-contrib/yiiframework.com

You can easily find tutorials on how to set up Gulp and Sass together.

Then you need to define an asset bundle where you reference the generated css.

Check the guide.

And you probably need to disable the ‘official’ Yii Bootstrap assets.

Here’s instructions: http://www.yiiframework.com/doc-2.0/guide-structure-assets.html#customizing-asset-bundles

Note that you can also go the route of configuring the asset manager to call the third-party tool-chain for you, but I haven’t really bothered.

Instructions here: http://www.yiiframework.com/doc-2.0/guide-structure-assets.html#asset-conversion

Personally, I just run a ‘gulp build’ or ‘gulp watch’ and then code…

Thank you very much for a quick as informative response.

I was actually looking at the Bootstrap framework download today when I was running out of ideas and noticed it was sass only. I had also installed node.js for this purpose and had played around with grunt.

So essentially you recommend ditching lessc preprocessing in favour of sass as Bootstrap 4 will be sass-only anyway and ignoring any intrinsic compilers etc in favour of a Node/Gulp setup, set up file watchers in Gulp and make the appropriate configurations in AssetManager so that it publishes only the compiled file from Gulp instead of the core Bootstrap extension (which I had disabled anyway)?

Exactly :)

That way you can use best of breed tool-sets all the way.

I think that you will find Gulp to be much more flexible and cleaner than Grunt, by the way.

But, that is a matter of preference.

However, if you don’t have preferences, choose Gulp.

Here’s a good article on SitePoint about Gulp for Sass: http://www.sitepoint.com/simple-gulpy-workflow-sass/

I’ve downloaded the yiiframework.com files and had a look at the set up you have.

Regarding the gulp, gulp-sass etc modules… are these installed locally to the project root or globally as node modules? I don’t see them in the project directory but this could obviously be due to .gitignore. If it’s possible, I would prefer to have these installed globally for 1) reuse and 2) less clutter in the project directory. Going by the require() statements in Gulpfile.js they need to be included locally (it seems obvious this could be done globally but it’s going to involve a considerable folder path).

Thanks again for the help! I’ve spent many a year doing various things in Yii, PHP etc but this work I am doing now is for a large project so I am hoping it will not only produce a lean and secure application but will also help me to really polish off the skills I have been learning over the years.

It would now be a good idea to read the readme :)

It is a bad idea to save the Gulp modules globally because - heck: why not store everything globally, then? Including all composer packages, like Yii?

The Gulp client is installed globally, though. And the Browser-sync tool.

The rest of project dependent, and you can treat ‘node_modules’ just as you treat the ‘vendor’ directory: something that is project specific.

Read the readme, and if anything is unclear, tell us :)

I’ve been playing around with this last night and most of today and I still cant seem to get it to work.

I had installed node globally and the packages locally, so my root directory looks like this: -




/backend

/common

/console

/development

/environments

/frontend

/node_modules

	/.bin

	/browser-synch

	/del

	/es6-promise

	/gulp

	/gulp-autoprefixer

	/gulp-cache

	/gulp-concat

	/gulp-imaginemin

	/gulp-jshint

	/gulp-minify-css

	/gulp-notify

	/gulp-rename

	/gulp-sass

	/gulp-sourcemaps

	/gulp-uglify

	/jshint

/scss

	/1-common

	/2-vendors

	/3-global

	/4-components

	/5-pages

	/6-elements

	all.css

/tests

/vendor

/web

	/css

gulpfile.js

package.json



I’ve stripped down gulpfile.js to a minimum to test the compiler prior to setting a watch or adding other functionality: -




// Load plugins

var gulp = require('gulp');

var sass = require('gulp-sass');


var sassOptions = {

    errLogToConsole: true,

    outputStyle: 'expanded'

};


// Styles

gulp.task('styles', function() {

    return gulp

        .src('scss/all.scss')

        .pipe(sass(sassOptions).on('error', sass.logError))

        .pipe(autoprefixer(autoprefixerOptions))

        .pipe(gulp.dest('web/css'))

        .pipe(notify({ message: 'Styles task complete' }));

});



So I have now tried running the console command but I get neither anything in the web/css folder nor any error messages.




node gulpfile styles



I have read through the README.md document and I cant see where I am going wrong here at all.

Again, all your help is greatly appreciated!

BTW I have the gulp client installed locally - I tried having just a global installation but it I was getting a cannot find module error.




# install gulp globally if you haven't done so before

npm install -g gulp


# install browsersync globally if you haven't done so before

npm install -g browser-sync


# install dependent NPM modules

npm install

Gulp is both global and local, btw.

Browser-sync, on the other hand, is global only.

How does your package.json look like?

The package.json file was the default copied over from the yiiframework.com github package: -




{

  "name": "yiiframework.com",

  "version": "2.0.0",

  "description": "yiiframework.com Website ========================",

  "main": "Gulpfile.js",

  "scripts": {

    "test": "echo \"Error: no test specified\" && exit 1"

  },

  "repository": {

    "type": "git",

    "url": "https://github.com/qiangxue/yiiframework.com.git"

  },

  "author": "Qiang Xue",

  "homepage": "http://www.yiiframework.com",

  "devDependencies": {

    "del": "^2.1.0",

    "gulp": "^3.9.0",

    "es6-promise": "*",

    "gulp-autoprefixer": "^3.1.0",

    "gulp-cache": "^0.4.0",

    "gulp-concat": "^2.6.0",

    "gulp-imagemin": "^2.4.0",

    "gulp-jshint": "^2.0.0",

    "gulp-minify-css": "^1.2.1",

    "gulp-notify": "^2.2.0",

    "gulp-rename": "^1.2.2",

    "gulp-sass": "^2.1.0",

    "gulp-sourcemaps": "^1.6.0",

    "gulp-uglify": "^1.5.1",

    "jshint": "^2.8.0"

  }

}




FYI I changed gulpfile.js to Gulpfile.js just to make sure it matched perfectly with the package.json but it didn’t help.

You should not have to do anything extra besides following the instructions in our readme :)

I assume that you have a recent Node.js installed?

Also, what errors exactly are you getting?

Yeah, I have node.js installed. The odd thing is that I am not getting any errors. This is really frustrating.

Wait: are you running node gulpfile build ?

You should just run:


gulp


gulp build


gulp whatever

That is: gulp is a global command.

It invokes node.js, not the other way around.

Boom! You were right on the money. I was sure I have tried that variant before but perhaps not (I’m quite brain-fried from trying to get Bootstrap to compile, including going from 10AM yesterday pretty much straight through til 2AM today).

Anyway, I am now getting messages that it is attempting to compile but there are a few errors I need to look at. Honestly, I don’t think I have ever been so happy to see error messages in my life.

Thanks again, Sir. It’s been a struggle to get the compile functionality but it’s rare that something worthwhile is easy and that’s a major task in the development of this application almost sorted, which is a relief.

Thanks again!

Awesome! :)

Stick with it because the knowledge that you are starting to pick up is applicable to much larger area of web development than just Yii projects.

I have modified the Gulpfile to handle the advanced project layout:


// fix problems with undefined Promise class

// http://stackoverflow.com/questions/32490328/gulp-autoprefixer-throwing-referenceerror-promise-is-not-defined

require('es6-promise').polyfill();


// Load plugins

var gulp = require('gulp'),

	sass = require('gulp-sass'),

	autoprefixer = require('gulp-autoprefixer'),

	minifycss = require('gulp-minify-css'),

	jshint = require('gulp-jshint'),

	uglify = require('gulp-uglify'),

	imagemin = require('gulp-imagemin'),

	rename = require('gulp-rename'),

	concat = require('gulp-concat'),

	notify = require('gulp-notify'),

	cache = require('gulp-cache'),

	browsersync = require('browser-sync'),

	sourcemaps = require('gulp-sourcemaps'),

	del = require('del');


	var sassOptions = {

  	errLogToConsole: true,

  	outputStyle: 'expanded'

	};


	var autoprefixerOptions = {

  	browsers: ['last 2 versions', '> 5%', 'Firefox ESR']

	};




// Styles

gulp.task('styles', function() {

  return gulp

	.src('scss/all.scss')

	.pipe(sourcemaps.init())

	.pipe(sass(sassOptions).on('error', sass.logError))

	.pipe(autoprefixer(autoprefixerOptions))

	.pipe(gulp.dest('frontend/web/css'))

	.pipe(gulp.dest('backend/web/css'))

	.pipe(rename({ suffix: '.min' }))

	.pipe(minifycss())

	.pipe(sourcemaps.write('../css/',{includeContent: false, sourceRoot: '../scss/'}))

	.pipe(gulp.dest('frontend/web/css'))

	.pipe(gulp.dest('backend/web/css'))

	.pipe(notify({ message: 'Styles task complete' }));

});


// Scripts

gulp.task('scripts', function() {

  return gulp.src(require('./js/all.json'))

	//.pipe(jshint('.jshintrc'))

	//.pipe(jshint.reporter('default'))

	.pipe(sourcemaps.init())

	.pipe(concat('all.js'))

	.pipe(gulp.dest('frontend/web/js'))

	.pipe(gulp.dest('backend/web/js'))

	.pipe(rename({ suffix: '.min' }))

	.pipe(uglify())

	.pipe(sourcemaps.write())

	.pipe(gulp.dest('frontend/web/js'))

	.pipe(gulp.dest('backend/web/js'))

	.pipe(notify({ message: 'Scripts task complete' }));

});


// Images

gulp.task('images', function() {

  return gulp.src('img/**/*')

	.pipe(cache(imagemin({ optimizationLevel: 3, progressive: true, interlaced: true })))

	.pipe(gulp.dest('web/img'))

	.pipe(notify({ message: 'Images task complete' }));

});


// Copy fonts

gulp.task('fonts', function() {

  gulp.src(['vendor/bower/bootstrap/fonts/*','scss/2-vendors/fontawesome/fonts/*', 'scss/2-vendors/fonts/josefine-sans/*'])

  .pipe(gulp.dest('./web/fonts'));

});


// Clean

gulp.task('clean', function(cb) {

	del(['frontend/web/css', 'frontend/web/js'], cb)

	del(['backend/web/css', 'backend/web/js'], cb)

});


// Build the "web" folder by running all of the above tasks

gulp.task('build', ['clean', 'styles', 'scripts'], function() {});


// Watch

gulp.task('watch', function() {


  // Initialize Browsersync

  browsersync.init({

	proxy: "http://bugitor.dev"

  });


  // Watch .scss files

  gulp.watch('scss/**/*.scss', ['styles']);


  // Watch .js files

  gulp.watch('js/**/*.js', ['scripts']);


  // Watch image files

  //gulp.watch('img/**/*', ['images']);


  // Watch any view files in 'views', reload on change

  gulp.watch(['common/views/**/*.php']).on('change', browsersync.reload);

  gulp.watch(['frontend/views/**/*.php']).on('change', browsersync.reload);

  gulp.watch(['backend/views/**/*.php']).on('change', browsersync.reload);


  // Watch any files in 'web', reload on change

  gulp.watch(['frontend/web/js/*']).on('change', browsersync.reload);

  gulp.watch(['backend/web/js/*']).on('change', browsersync.reload);

  gulp.watch(['frontend/web/css/*']).on('change', browsersync.reload);

  gulp.watch(['backend/web/css/*']).on('change', browsersync.reload);

});


gulp.task('default', ['build', 'watch'], function() {});



Yep, that’s the beauty of true application development - simplifying the manifold and then applying that simplification to a manifold of situations :)

Thank you!

I will definitely look to apply this very soon but that will have to be after I have looked through it, understood the functionality of all the modules etc rather than just blindly plugging it in.

Right now, I am going to get those errors sorted out and do a test compile. Then I will probably look to strip out unwanted style/scripts for Bootstrap elements my project is not going to use (or at least not in the initial version) to keep things as lean and simple as I possibly can.

That’s it successfully compiling from the source files for Bootstrap 3.3.6 now. Thanks!