diff --git a/docs/project-generation-options.rst b/docs/project-generation-options.rst
index 5a0cffe6..d1d36324 100644
--- a/docs/project-generation-options.rst
+++ b/docs/project-generation-options.rst
@@ -73,7 +73,9 @@ js_task_runner [1]
3. None
custom_bootstrap_compilation [n]
- If you use Grunt, scaffold out recompiling Bootstrap as as task. (Useful for letting you change Bootstrap variables in real time.) Consult project README for more details.
+ Scaffold out recompiling Bootstrap as as task, with Gulp_ or Grunt_.
+ Useful for letting you change Bootstrap variables in real time.
+ Consult project README for more details.
open_source_license [1]
Select a software license for the project. The choices are:
diff --git a/{{cookiecutter.project_slug}}/Gruntfile.js b/{{cookiecutter.project_slug}}/Gruntfile.js
index 6900c4e0..15384c67 100644
--- a/{{cookiecutter.project_slug}}/Gruntfile.js
+++ b/{{cookiecutter.project_slug}}/Gruntfile.js
@@ -61,7 +61,7 @@ module.exports = function (grunt) {
options: {
outputStyle: 'nested',
{% if cookiecutter.custom_bootstrap_compilation == 'y' %}
- includePaths: ['bower_components/bootstrap-sass/assets/stylesheets/bootstrap/'],
+ includePaths: ['node_modules/bootstrap/scss'],
{% endif %}
sourceMap: false,
precision: 10
@@ -74,7 +74,7 @@ module.exports = function (grunt) {
options: {
outputStyle: 'compressed',
{% if cookiecutter.custom_bootstrap_compilation == 'y' %}
- includePaths: ['bower_components/bootstrap-sass/assets/stylesheets/bootstrap/'],
+ includePaths: ['node_modules/bootstrap/scss'],
{% endif %}
sourceMap: false,
precision: 10
diff --git a/{{cookiecutter.project_slug}}/README.rst b/{{cookiecutter.project_slug}}/README.rst
index 06dd82ed..dc3495d5 100644
--- a/{{cookiecutter.project_slug}}/README.rst
+++ b/{{cookiecutter.project_slug}}/README.rst
@@ -137,8 +137,16 @@ See detailed `cookiecutter-django Docker documentation`_.
Custom Bootstrap Compilation
^^^^^^
-To get automatic Bootstrap recompilation with variables of your choice, install bootstrap sass (`bower install bootstrap-sass`) and tweak your variables in `static/sass/custom_bootstrap_vars`.
+The generated CSS is set up with automatic Bootstrap recompilation with variables of your choice.
+Bootstrap v4 is installed using npm and customised by tweaking your variables in ``static/sass/custom_bootstrap_vars``.
-(You can find a list of available variables [in the bootstrap-sass source](https://github.com/twbs/bootstrap-sass/blob/master/assets/stylesheets/bootstrap/_variables.scss), or get explanations on them in the [Bootstrap docs](https://getbootstrap.com/customize/).)
+You can find a list of available variables `in the bootstrap source`_, or get explanations on them in the `Bootstrap docs`_.
+
+{% if cookiecutter.js_task_runner == 'Gulp' %}
+Bootstrap's javascript as well as its dependencies is concatenated into a single file: ``static/js/vendors.js``.
+{% endif %}
+
+.. _in the bootstrap source: https://github.com/twbs/bootstrap/blob/v4-dev/scss/_variables.scss
+.. _Bootstrap docs: https://getbootstrap.com/docs/4.0/getting-started/theming/
{% endif %}
diff --git a/{{cookiecutter.project_slug}}/gulpfile.js b/{{cookiecutter.project_slug}}/gulpfile.js
index 594fa090..bb18a535 100644
--- a/{{cookiecutter.project_slug}}/gulpfile.js
+++ b/{{cookiecutter.project_slug}}/gulpfile.js
@@ -10,6 +10,9 @@ var gulp = require('gulp'),
sass = require('gulp-sass'),
autoprefixer = require('gulp-autoprefixer'),
cssnano = require('gulp-cssnano'),
+ {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
+ concat = require('gulp-concat'),
+ {% endif %}
rename = require('gulp-rename'),
del = require('del'),
plumber = require('gulp-plumber'),
@@ -25,15 +28,24 @@ var gulp = require('gulp'),
// Relative paths function
var pathsConfig = function (appName) {
this.app = "./" + (appName || pjson.name);
+ var vendorsRoot = 'node_modules/';
return {
+ {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
+ bootstrapSass: vendorsRoot + '/bootstrap/scss',
+ vendorsJs: [
+ vendorsRoot + 'jquery/dist/jquery.slim.js',
+ vendorsRoot + 'popper.js/dist/umd/popper.js',
+ vendorsRoot + 'bootstrap/dist/js/bootstrap.js'
+ ],
+ {% endif %}
app: this.app,
templates: this.app + '/templates',
css: this.app + '/static/css',
sass: this.app + '/static/sass',
fonts: this.app + '/static/fonts',
images: this.app + '/static/images',
- js: this.app + '/static/js',
+ js: this.app + '/static/js'
}
};
@@ -45,8 +57,15 @@ var paths = pathsConfig();
// Styles autoprefixing and minification
gulp.task('styles', function() {
- return gulp.src(paths.sass + '/*.scss')
- .pipe(sass().on('error', sass.logError))
+ return gulp.src(paths.sass + '/project.scss')
+ .pipe(sass({
+ includePaths: [
+ {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
+ paths.bootstrapSass,
+ {% endif %}
+ paths.sass
+ ]
+ }).on('error', sass.logError))
.pipe(plumber()) // Checks for errors
.pipe(autoprefixer({browsers: ['last 2 versions']})) // Adds vendor prefixes
.pipe(pixrem()) // add fallbacks for rem units
@@ -65,6 +84,20 @@ gulp.task('scripts', function() {
.pipe(gulp.dest(paths.js));
});
+
+{% if cookiecutter.custom_bootstrap_compilation == 'y' %}
+// Vendor Javascript minification
+gulp.task('vendor-scripts', function() {
+ return gulp.src(paths.vendorsJs)
+ .pipe(concat('vendors.js'))
+ .pipe(gulp.dest(paths.js))
+ .pipe(plumber()) // Checks for errors
+ .pipe(uglify()) // Minifies the js
+ .pipe(rename({ suffix: '.min' }))
+ .pipe(gulp.dest(paths.js));
+});
+{% endif %}
+
// Image compression
gulp.task('imgCompression', function(){
return gulp.src(paths.images + '/*')
@@ -101,5 +134,5 @@ gulp.task('watch', function() {
// Default task
gulp.task('default', function() {
- runSequence(['styles', 'scripts', 'imgCompression'], ['runServer', 'browserSync', 'watch']);
+ runSequence(['styles', 'scripts', {% if cookiecutter.custom_bootstrap_compilation == 'y' %}'vendor-scripts', {% endif %}'imgCompression'], ['runServer', 'browserSync', 'watch']);
});
diff --git a/{{cookiecutter.project_slug}}/package.json b/{{cookiecutter.project_slug}}/package.json
index 0c8af427..a37d73bf 100644
--- a/{{cookiecutter.project_slug}}/package.json
+++ b/{{cookiecutter.project_slug}}/package.json
@@ -5,6 +5,9 @@
"devDependencies": {
{% if cookiecutter.js_task_runner == 'Grunt' %}
"autoprefixer-core": "~5.2.1",
+ {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
+ "bootstrap": "^4.0.0",
+ {% endif %}
"connect-livereload": "~0.3.2",
"cssnano": "~2.1.0",
"grunt": "~0.4.5",
@@ -12,14 +15,26 @@
"grunt-contrib-watch": "~0.6.1",
"grunt-postcss": "~0.5.5",
"grunt-sass": "~1.0.0",
+ {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
+ "jquery": "^3.2.1-slim",
+ {% endif %}
"load-grunt-tasks": "~3.2.0",
"pixrem": "~1.3.1",
+ {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
+ "popper.js": "^1.12.3",
+ {% endif %}
"time-grunt": "~1.2.1"
{% elif cookiecutter.js_task_runner == 'Gulp' %}
+ {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
+ "bootstrap": "^4.0.0",
+ {% endif %}
"browser-sync": "^2.14.0",
"del": "^2.2.2",
"gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.1",
+ {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
+ "gulp-concat": "^2.6.1",
+ {% endif %}
"gulp-cssnano": "^2.1.2",
"gulp-imagemin": "^3.0.3",
"gulp-pixrem": "^1.0.0",
@@ -28,6 +43,10 @@
"gulp-sass": "^2.3.2",
"gulp-uglify": "^2.0.0",
"gulp-util": "^3.0.7",
+ {% if cookiecutter.custom_bootstrap_compilation == 'y' %}
+ "jquery": "^3.2.1-slim",
+ "popper.js": "^1.12.3",
+ {% endif %}
"run-sequence": "^1.2.2"
{% endif %}
},
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/sass/project.scss b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/sass/project.scss
index 6e701f29..3ba2e55a 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/sass/project.scss
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/static/sass/project.scss
@@ -1,54 +1,6 @@
{% if cookiecutter.custom_bootstrap_compilation == 'y' %}
-@import "variables";
@import "custom_bootstrap_vars";
-@import "mixins";
-
-// Reset and dependencies
-@import "normalize";
-@import "print";
-@import "glyphicons";
-
-// Core CSS
-@import "scaffolding";
-@import "type";
-@import "code";
-@import "grid";
-@import "tables";
-@import "forms";
-@import "buttons";
-
-// Components
-@import "component-animations";
-@import "dropdowns";
-@import "button-groups";
-@import "input-groups";
-@import "navs";
-@import "navbar";
-@import "breadcrumbs";
-@import "pagination";
-@import "pager";
-@import "labels";
-@import "badges";
-@import "jumbotron";
-@import "thumbnails";
-@import "alerts";
-@import "progress-bars";
-@import "media";
-@import "list-group";
-@import "panels";
-@import "responsive-embed";
-@import "wells";
-@import "close";
-
-// Components w/ JavaScript
-@import "modals";
-@import "tooltip";
-@import "popovers";
-@import "carousel";
-
-// Utility classes
-@import "utilities";
-@import "responsive-utilities";
+@import "bootstrap";
{% endif %}
diff --git a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html
index 6fdc1798..a45de763 100644
--- a/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html
+++ b/{{cookiecutter.project_slug}}/{{cookiecutter.project_slug}}/templates/base.html
@@ -14,13 +14,19 @@
{% block css %}
+ {% endraw %}{% if cookiecutter.custom_bootstrap_compilation == "n" %}{% raw %}
+ {% endraw %}{% endif %}{% raw %}
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress css %}{% endraw %}{% endif %}{% raw %}
+ {% endraw %}{% if cookiecutter.js_task_runner == "Gulp" %}{% raw %}
+
+ {% endraw %}{% else %}{% raw %}
+ {% endraw %}{% endif %}{% raw %}
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %}
{% endblock %}
@@ -88,12 +94,19 @@
================================================== -->
{% block javascript %}
+ {% endraw %}{% if cookiecutter.custom_bootstrap_compilation == "y" and cookiecutter.js_task_runner == "Gulp" %}{% raw %}
+
+ {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress js %}{% endraw %}{% endif %}{% raw %}
+
+ {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %}
+ {% endraw %}{% else %}{% raw %}
+ {% endraw %}{% endif %}{% raw %}
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress js %}{% endraw %}{% endif %}{% raw %}