Node.JS + docker-compose = ♥ (#1128)

* Introduce static asset build infrastructure

* Enhance gulpfile.js

* Introduce node service

* BrowserSync debug-only support

* Remove newline before  BrowserSync debug-only support section

* FIx node Dockerfile package.json COPY

* Try fiixing node Dockerfile package.json COPY ones again

* Switch to `node:7-slim`

* Try switching to node:6

To account for possible node:7 docker-compose incompatibiltiy

* Revert "Try switching to node:6"

This reverts commit 62cc02df1a.

* Try switcging workdir to /app

* Try utilizing relative package.json path

* Resetting to the last version working locally with docker-compose 1.11.x

* Build upon the latest node:7.9-slim

* Stop dockerignoring package.json

* Fix typo

* Try a different package.json path

* Revert "Try a different package.json path"

This reverts commit f29f8500b8.

* Revert "Fix typo"

This reverts commit 02033729b5.

* Revert "Stop dockerignoring package.json"

This reverts commit 63c5491546.

* Upgrade docker-engine and docker-compose used by Travis CI

* Fix .travis.yml comments

* Inline docker-engine and docker-compose versions

* DEBUG: pwd

* Revert "DEBUG: pwd "

This reverts commit 6c2ed4321a.

* Try copying package.json to the same dir as node Dockerfile's

* Revert "Try copying package.json to the same dir as node Dockerfile's"

This reverts commit 24340a0783.

* Try out node:7.9

* Revert "Try out node:7.9"

This reverts commit 32286d33c2.

* Revert "Upgrade docker-engine and docker-compose used by Travis CI"

* Get rid of npm-check-updates

Reason: Reserved for the upcoming PR

* Get rid of npm-check

Reason: Reserved for the upcoming PR

* Get rid of 'standard' npm package

Reason: Reserved for the upcoming PR

* Clean up package.json

* Preserve package.json uncoditionally

Since we now have *unconditional* node.js integration, `package.json` must be out there whenever `node` service gets built

* Upgrade node service image to 7.10

* Document Node.js-Docker integration

* Fix gulpfile.js images region name

* Get rid of Gulp migrate task

* Document Gulp-Docker integration

* Introduce static asset build infrastructure

* Enhance gulpfile.js

* Introduce node service

* BrowserSync debug-only support

* Remove newline before  BrowserSync debug-only support section

* FIx node Dockerfile package.json COPY

* Try fiixing node Dockerfile package.json COPY ones again

* Switch to `node:7-slim`

* Try switching to node:6

To account for possible node:7 docker-compose incompatibiltiy

* Revert "Try switching to node:6"

This reverts commit 62cc02df1a.

* Try switcging workdir to /app

* Try utilizing relative package.json path

* Resetting to the last version working locally with docker-compose 1.11.x

* Build upon the latest node:7.9-slim

* Stop dockerignoring package.json

* Revert "Stop dockerignoring package.json"

This reverts commit 63c5491546.

* Fix typo

* Revert "Fix typo"

This reverts commit 02033729b5.

* Try a different package.json path

* Revert "Try a different package.json path"

This reverts commit f29f8500b8.

* Upgrade docker-engine and docker-compose used by Travis CI

* Fix .travis.yml comments

* Inline docker-engine and docker-compose versions

* DEBUG: pwd

* Revert "DEBUG: pwd "

This reverts commit 6c2ed4321a.

* Try copying package.json to the same dir as node Dockerfile's

* Revert "Try copying package.json to the same dir as node Dockerfile's"

This reverts commit 24340a0783.

* Try out node:7.9

* Revert "Try out node:7.9"

This reverts commit 32286d33c2.

* Revert "Upgrade docker-engine and docker-compose used by Travis CI"

* Get rid of npm-check-updates

Reason: Reserved for the upcoming PR

* Get rid of npm-check

Reason: Reserved for the upcoming PR

* Get rid of 'standard' npm package

Reason: Reserved for the upcoming PR

* Clean up package.json

* Preserve package.json uncoditionally

Since we now have *unconditional* node.js integration, `package.json` must be out there whenever `node` service gets built

* Upgrade node service image to 7.10

* Document Node.js-Docker integration

* Fix gulpfile.js images region name

* Get rid of Gulp migrate task

* Document Gulp-Docker integration

* Remove Gulp-Docker integraton not supported initialization message
This commit is contained in:
Shupeyko Nikita 2017-06-20 22:48:17 +03:00 committed by GitHub
parent ec62188fae
commit 4b06fe3958
21 changed files with 423 additions and 164 deletions

View File

@ -6,6 +6,8 @@ Getting Up and Running Locally With Docker
The steps below will get you up and running with a local development environment. The steps below will get you up and running with a local development environment.
All of these commands assume you are in the root of your generated project. All of these commands assume you are in the root of your generated project.
.. _devlocdocker-prereq:
Prerequisites Prerequisites
------------- -------------
@ -30,6 +32,9 @@ Currently PostgreSQL (``psycopg2`` python package) is not installed inside Docke
Doing this will prevent the project from being installed in an Windows-only environment (thus without usage of Docker). If you want to use this project without Docker, make sure to remove ``psycopg2`` from the requirements again. Doing this will prevent the project from being installed in an Windows-only environment (thus without usage of Docker). If you want to use this project without Docker, make sure to remove ``psycopg2`` from the requirements again.
.. _devlocdocker-build-the-stack:
Build the Stack Build the Stack
--------------- ---------------
@ -40,6 +45,9 @@ on your development system::
If you want to build the production environment you don't have to pass an argument -f, it will automatically use docker-compose.yml. If you want to build the production environment you don't have to pass an argument -f, it will automatically use docker-compose.yml.
.. _devlocdocker-boot-the-system:
Boot the System Boot the System
--------------- ---------------

76
docs/gulp-with-docker.rst Normal file
View File

@ -0,0 +1,76 @@
Gulp with Docker
================
.. index:: gulp, gulpjs, gulpfile, gulpfilejs, docker, docker-compose
`Gulp`_ support is provided out-of-the-box, ready for use as-is, or with any kind of customizations suiting the specific needs of the project.
.. _`Gulp`: http://gulpjs.com/
*All paths are relative to the generated project's root.*
Prerequisites
-------------
- These :ref:`nodewithdocker-prereq` are satisfied.
Overview
--------
:ref:`nodewithdocker-overview` Node.js integration details first to get the whole picture.
Essential aspects of Gulp integration are
- :code:`./gulpfile.js` with Gulp tasks defined;
- :code:`./{{ cookiecutter.project_slug }}/static/build/` (build directory) with static assets built via Gulp.
Let us take a closer look at :code:`./gulpfile.js`:
- paths to static assets are provided by :code:`pathsConfig()`;
- for clarity, related tasks are grouped by :code:`region`:
- :code:`images`:
- :code:`images`: run image-related tasks in parallel, namely:
- :code:`favicons-images`: process favicon images only;
- :code:`nonfavicons-images`: process all images except for favicons.
- :code:`scripts`:
- :code:`scripts`: run script-related tasks in sequence, namely:
- :code:`js-scripts`: process js scripts.
- :code:`styles`:
- :code:`styles`: run script-related tasks in sequence, namely:
- :code:`sass-styles`: process SCSS styles;
- :code:`css-styles`: process CSS styles.
- :code:`build`:
- :code:`build`: run :code:`images`, :code:`scripts`, and :code:`styles` in parallel;
- :code:`clean-build`: clean up build directory:
- the :code:`default` task runs the following ones in sequence:
- :code:`build`;
- :code:`init-browserSync`: initialize `BrowserSync`_;
- :code:`watch`: watch static asset files/directories changes, running BrowserSync on any changes.
.. _`BrowserSync`: https://www.browsersync.io/
Workflow
--------
#. [*skip if done*] :ref:`devlocdocker-build-the-stack`;
#. :ref:`devlocdocker-boot-the-system`.
By default, :code:`gulp` command gets executed immediately after :code:`node`
container startup (see :code:`./dev.yml` for details) which in turn invokes
the :code:`default` task, so generally one would not need to run any
of the aforementioned tasks manually. However, should the need arise,
oftentimes just a few of the tasks listed above will be used to, for instance,
straightforwardly :code:`build` all assets
.. code-block:: bash
$ docker-compose -f dev.yml exec node gulp build
or build :code:`scripts` selectively
.. code-block:: bash
$ docker-compose -f dev.yml exec node gulp scripts

View File

@ -17,6 +17,8 @@ Contents:
developing-locally-docker developing-locally-docker
settings settings
linters linters
nodejs-with-docker
gulp-with-docker
live-reloading-and-sass-compilation live-reloading-and-sass-compilation
deployment-on-pythonanywhere deployment-on-pythonanywhere
deployment-on-heroku deployment-on-heroku

View File

@ -0,0 +1,45 @@
Node.js with Docker
===================
.. index:: node, nodejs, docker, docker-compose
`Node.js`_ support is provided out-of-the-box, ready for use as-is, or with any kind of customizations suiting the specific needs of the project.
.. _`Node.js`: https://nodejs.org/en/
*All paths are relative to the generated project's root.*
.. _nodewithdocker-prereq:
Prerequisites
-------------
- The project was generated with :code:`use_docker` set to :code:`y`.
- These :ref:`devlocdocker-prereq` are met as well.
.. _nodewithdocker-overview:
Overview
--------
Essential aspects of Node.js integration are
- node docker-compose service (:code:`node`) definition in :code:`./dev.yml`;
- :code:`./compose/node/Dockerfile-dev` defining the :code:`node` image;
- :code:`./node_modules/` 'overlayed' with :code:`/app/node_modules/`, its counterpart from the running instance of :code:`node`.
Workflow
--------
#. [*skip if done*] :ref:`devlocdocker-build-the-stack`:
- when building :code:`node` image from scratch, dependencies from :code:`package.json` are installed.
#. :ref:`devlocdocker-boot-the-system`.
To log the running :code:`node` container's activity,
.. code-block:: bash
$ docker-compose -f dev.yml logs node

View File

@ -256,7 +256,6 @@ elif '{{ cookiecutter.js_task_runner}}'.lower() == 'grunt':
else: else:
remove_gulp_files() remove_gulp_files()
remove_grunt_files() remove_grunt_files()
remove_packageJSON_file()
# 7. Removes all certbot/letsencrypt files if it isn't going to be used # 7. Removes all certbot/letsencrypt files if it isn't going to be used
if '{{ cookiecutter.use_lets_encrypt }}'.lower() != 'y': if '{{ cookiecutter.use_lets_encrypt }}'.lower() != 'y':
@ -264,11 +263,10 @@ if '{{ cookiecutter.use_lets_encrypt }}'.lower() != 'y':
# 8. Display a warning if use_docker and use_grunt are selected. Grunt isn't # 8. Display a warning if use_docker and use_grunt are selected. Grunt isn't
# supported by our docker config atm. # supported by our docker config atm.
if '{{ cookiecutter.js_task_runner }}'.lower() in ['grunt', 'gulp'] and '{{ cookiecutter.use_docker }}'.lower() == 'y': if '{{ cookiecutter.js_task_runner }}'.lower() in ['grunt'] and '{{ cookiecutter.use_docker }}'.lower() == 'y':
print( print(
"You selected to use docker and a JS task runner. This is NOT supported out of the box for now. You " "You selected to use Docker and Grunt task runner. This is NOT supported out of the box for now. You "
"can continue to use the project like you normally would, but you will need to add a " "can continue to use the project like you normally would, but you will need to setup Grunt manually."
"js task runner service to your docker configuration manually."
) )
# 9. Removes the certbot/letsencrypt files and display a warning if use_lets_encrypt is selected and use_docker isn't. # 9. Removes the certbot/letsencrypt files and display a warning if use_lets_encrypt is selected and use_docker isn't.

View File

@ -79,3 +79,4 @@ staticfiles/
.cache/ .cache/
{{ cookiecutter.project_slug }}/static/build/

View File

@ -0,0 +1,11 @@
FROM node:7.10-slim
RUN mkdir -p /app
COPY ./package.json /app
WORKDIR /app
RUN npm install && npm cache clean
ENV PATH ./node_modules/.bin/:$PATH

View File

@ -184,9 +184,10 @@ STATIC_ROOT = str(ROOT_DIR('staticfiles'))
# See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url # See: https://docs.djangoproject.com/en/dev/ref/settings/#static-url
STATIC_URL = '/static/' STATIC_URL = '/static/'
_STATIC_BUILD_ROOT_DIR_NAME = 'build'
# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS # See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#std:setting-STATICFILES_DIRS
STATICFILES_DIRS = [ STATICFILES_DIRS = [
str(APPS_DIR.path('static')), (_STATIC_BUILD_ROOT_DIR_NAME, str(APPS_DIR.path('static').path(_STATIC_BUILD_ROOT_DIR_NAME))),
] ]
# See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders # See: https://docs.djangoproject.com/en/dev/ref/contrib/staticfiles/#staticfiles-finders

View File

@ -21,6 +21,7 @@ services:
depends_on: depends_on:
- postgres{% if cookiecutter.use_mailhog == 'y' %} - postgres{% if cookiecutter.use_mailhog == 'y' %}
- mailhog{% endif %} - mailhog{% endif %}
- node
environment: environment:
- POSTGRES_USER={{cookiecutter.project_slug}} - POSTGRES_USER={{cookiecutter.project_slug}}
- USE_DOCKER=yes - USE_DOCKER=yes
@ -48,3 +49,19 @@ services:
ports: ports:
- "8025:8025" - "8025:8025"
{% endif %} {% endif %}
node:
build:
context: .
dockerfile: ./compose/node/Dockerfile-dev
volumes:
- .:/app
# http://jdlm.info/articles/2016/03/06/lessons-building-node-app-docker.html
- /app/node_modules
command: "gulp"
ports:
# BrowserSync port.
- "3000:3000"
# BrowserSync UI port.
- "3001:3001"

View File

@ -1,105 +1,139 @@
const gulp = require('gulp')
const pump = require('pump')
const sass = require('gulp-sass')
const pjson = require('./package.json')
const autoprefixer = require('gulp-autoprefixer')
const cleanCSS = require('gulp-clean-css')
const rename = require('gulp-rename')
const pixrem = require('gulp-pixrem')
const concat = require('gulp-concat')
const uglify = require('gulp-uglify')
const imagemin = require('gulp-imagemin')
const clean = require('gulp-clean')
const spawn = require('child_process').spawn
const runSequence = require('run-sequence')
const browserSync = require('browser-sync').create()
const pathsConfig = function (appName) {
this.paths = {}
//////////////////////////////// this.paths['app'] = './' + (appName || pjson.name)
//Setup//
////////////////////////////////
// Plugins this.paths['static'] = this.paths['app'] + '/static'
var gulp = require('gulp'),
pjson = require('./package.json'),
gutil = require('gulp-util'),
sass = require('gulp-sass'),
autoprefixer = require('gulp-autoprefixer'),
cssnano = require('gulp-cssnano'),
rename = require('gulp-rename'),
del = require('del'),
plumber = require('gulp-plumber'),
pixrem = require('gulp-pixrem'),
uglify = require('gulp-uglify'),
imagemin = require('gulp-imagemin'),
spawn = require('child_process').spawn,
runSequence = require('run-sequence'),
browserSync = require('browser-sync').create(),
reload = browserSync.reload;
this.paths['build'] = this.paths['static'] + '/build'
// Relative paths function this.paths['buildImages'] = this.paths['build'] + '/images'
var pathsConfig = function (appName) { this.paths['images'] = this.paths['static'] + '/images'
this.app = "./" + (appName || pjson.name); this.paths['images_files'] = this.paths['images'] + '/*'
this.paths['buildImagesFavicons'] = this.paths['buildImages'] + '/favicons'
this.paths['imagesFavicons'] = this.paths['images'] + '/favicons'
this.paths['imagesFavicons_files'] = this.paths['imagesFavicons'] + '/*'
return { this.paths['build_scriptsFileName'] = 'scripts.js'
app: this.app, this.paths['scripts'] = this.paths['static'] + '/scripts'
templates: this.app + '/templates', this.paths['scripts_files'] = this.paths['scripts'] + '/**/*'
css: this.app + '/static/css', this.paths['scriptsJs'] = this.paths['scripts'] + '/js'
sass: this.app + '/static/sass', this.paths['scriptsJs_files'] = this.paths['scriptsJs'] + '/*.js'
fonts: this.app + '/static/fonts',
images: this.app + '/static/images', this.paths['build_stylesFileName'] = 'styles.css'
js: this.app + '/static/js', this.paths['styles'] = this.paths['static'] + '/styles'
this.paths['styles_files'] = this.paths['styles'] + '/**/*'
this.paths['stylesSass'] = this.paths['styles'] + '/sass'
this.paths['stylesSass_files'] = this.paths['stylesSass'] + '/*.scss'
this.paths['stylesCss'] = this.paths['styles'] + '/css'
this.paths['stylesCss_files'] = this.paths['stylesCss'] + '/*.css'
this.paths['templates'] = this.paths['app'] + '/templates'
this.paths['templates_files'] = this.paths['templates'] + '/**/*.html'
return this.paths
} }
}; const paths = pathsConfig()
var paths = pathsConfig(); // region images
gulp.task('favicons-images', function (cb) {
pump([gulp.src(paths.imagesFavicons_files),
gulp.dest(paths.buildImagesFavicons)],
cb)
})
//////////////////////////////// gulp.task('nonfavicons-images', function (cb) {
//Tasks// pump([gulp.src(paths.images_files),
//////////////////////////////// imagemin(),
gulp.dest(paths.buildImages)],
cb)
})
// Styles autoprefixing and minification gulp.task('images', function () {
gulp.task('styles', function() { runSequence(['favicons-images', 'nonfavicons-images'])
return gulp.src(paths.sass + '/project.scss') })
.pipe(sass().on('error', sass.logError)) // endregion
.pipe(plumber()) // Checks for errors
.pipe(autoprefixer({browsers: ['last 2 versions']})) // Adds vendor prefixes // region scripts
.pipe(pixrem()) // add fallbacks for rem units gulp.task('js-scripts', function (cb) {
.pipe(gulp.dest(paths.css)) pump([gulp.src(paths.scriptsJs_files),
.pipe(rename({ suffix: '.min' })) concat(paths.build_scriptsFileName),
.pipe(cssnano()) // Minifies the result uglify(),
.pipe(gulp.dest(paths.css)); rename({suffix: '.min'}),
}); gulp.dest(paths.build)],
cb)
})
// Javascript minification
gulp.task('scripts', function () { gulp.task('scripts', function () {
return gulp.src(paths.js + '/project.js') runSequence('js-scripts')
.pipe(plumber()) // Checks for errors })
.pipe(uglify()) // Minifies the js // endregion
.pipe(rename({ suffix: '.min' }))
.pipe(gulp.dest(paths.js));
});
// Image compression // region styles
gulp.task('imgCompression', function(){ gulp.task('sass-styles', function (cb) {
return gulp.src(paths.images + '/*') pump([gulp.src(paths.stylesSass_files),
.pipe(imagemin()) // Compresses PNG, JPEG, GIF and SVG images sass(),
.pipe(gulp.dest(paths.images)) gulp.dest(paths.stylesCss)],
}); cb
)
})
// Run django server gulp.task('css-styles', function (cb) {
gulp.task('runServer', function(cb) { pump([gulp.src(paths.stylesCss_files),
var cmd = spawn('python', ['manage.py', 'runserver'], {stdio: 'inherit'}); concat(paths.build_stylesFileName),
cmd.on('close', function(code) { autoprefixer({browsers: ['last 2 versions']}),
console.log('runServer exited with code ' + code); pixrem(),
cb(code); cleanCSS({rebaseTo: '../../'}),
}); rename({suffix: '.min'}),
}); gulp.dest(paths.build)],
cb)
})
// Browser sync server for live reload gulp.task('styles', function () {
gulp.task('browserSync', function() { runSequence('sass-styles', 'css-styles')
browserSync.init( })
[paths.css + "/*.css", paths.js + "*.js", paths.templates + '*.html'], { // endregion
proxy: "localhost:8000"
}); // region build
}); gulp.task('build', function () {
runSequence(['images', 'scripts', 'styles'])
})
gulp.task('clean-build', function (cb) {
pump([gulp.src(paths.build),
clean()],
cb)
})
// endregion
gulp.task('init-browserSync', function () {
browserSync.init({
host: 'localhost:8000'
})
})
// Watch
gulp.task('watch', function () { gulp.task('watch', function () {
gulp.watch(paths.images_files, ['images']).on('change', browserSync.reload)
gulp.watch(paths.scripts_files, ['scripts']).on('change', browserSync.reload)
gulp.watch(paths.styles_files, ['styles']).on('change', browserSync.reload)
gulp.watch(paths.templates_files).on('change', browserSync.reload)
})
gulp.watch(paths.sass + '/*.scss', ['styles']);
gulp.watch(paths.js + '/*.js', ['scripts']).on("change", reload);
gulp.watch(paths.images + '/*', ['imgCompression']);
gulp.watch(paths.templates + '/**/*.html').on("change", reload);
});
// Default task
gulp.task('default', function () { gulp.task('default', function () {
runSequence(['styles', 'scripts', 'imgCompression'], 'runServer', 'browserSync', 'watch'); runSequence('build', 'init-browserSync', 'watch')
}); })

View File

@ -16,18 +16,18 @@
"pixrem": "~1.3.1", "pixrem": "~1.3.1",
"time-grunt": "~1.2.1" "time-grunt": "~1.2.1"
{% elif cookiecutter.js_task_runner == 'Gulp' %} {% elif cookiecutter.js_task_runner == 'Gulp' %}
"browser-sync": "^2.14.0", "browser-sync": "^2.18.8",
"del": "^2.2.2",
"gulp": "^3.9.1", "gulp": "^3.9.1",
"gulp-autoprefixer": "^3.1.1", "gulp-autoprefixer": "^3.1.1",
"gulp-cssnano": "^2.1.2", "gulp-clean": "^0.3.2",
"gulp-imagemin": "^3.0.3", "gulp-clean-css": "^3.0.4",
"gulp-concat": "^2.6.1",
"gulp-imagemin": "^3.1.1",
"gulp-pixrem": "^1.0.0", "gulp-pixrem": "^1.0.0",
"gulp-plumber": "^1.1.0",
"gulp-rename": "^1.2.2", "gulp-rename": "^1.2.2",
"gulp-sass": "^2.3.2", "gulp-sass": "^3.1.0",
"gulp-uglify": "^2.0.0", "gulp-uglify": "^2.1.2",
"gulp-util": "^3.0.7", "pump": "^1.0.2",
"run-sequence": "^1.2.2" "run-sequence": "^1.2.2"
{% endif %} {% endif %}
}, },

View File

@ -1,38 +0,0 @@
/* These styles are generated from project.scss. */
.alert-debug {
color: black;
background-color: white;
border-color: #d6e9c6;
}
.alert-error {
color: #b94a48;
background-color: #f2dede;
border-color: #eed3d7;
}
/* This is a fix for the bootstrap4 alpha release */
@media (max-width: 47.9em) {
.navbar-nav .nav-item {
float: none;
width: 100%;
display: inline-block;
}
.navbar-nav .nav-item + .nav-item {
margin-left: 0;
}
.nav.navbar-nav.pull-xs-right {
float: none !important;
}
}
/* Display django-debug-toolbar.
See https://github.com/django-debug-toolbar/django-debug-toolbar/issues/742
and https://github.com/pydanny/cookiecutter-django/issues/317
*/
[hidden][style="display: block;"] {
display: block !important;
}

View File

@ -1,21 +0,0 @@
/* Project specific Javascript goes here. */
/*
Formatting hack to get around crispy-forms unfortunate hardcoding
in helpers.FormHelper:
if template_pack == 'bootstrap4':
grid_colum_matcher = re.compile('\w*col-(xs|sm|md|lg|xl)-\d+\w*')
using_grid_layout = (grid_colum_matcher.match(self.label_class) or
grid_colum_matcher.match(self.field_class))
if using_grid_layout:
items['using_grid_layout'] = True
Issues with the above approach:
1. Fragile: Assumes Bootstrap 4's API doesn't change (it does)
2. Unforgiving: Doesn't allow for any variation in template design
3. Really Unforgiving: No way to override this behavior
4. Undocumented: No mention in the documentation, or it's too hard for me to find
*/
$('.form-group').removeClass('row');

View File

@ -0,0 +1,21 @@
/* Project specific Javascript goes here. */
/*
Formatting hack to get around crispy-forms unfortunate hardcoding
in helpers.FormHelper:
if template_pack == 'bootstrap4':
grid_colum_matcher = re.compile('\w*col-(xs|sm|md|lg|xl)-\d+\w*')
using_grid_layout = (grid_colum_matcher.match(self.label_class) or
grid_colum_matcher.match(self.field_class))
if using_grid_layout:
items['using_grid_layout'] = True
Issues with the above approach:
1. Fragile: Assumes Bootstrap 4's API doesn't change (it does)
2. Unforgiving: Doesn't allow for any variation in template design
3. Really Unforgiving: No way to override this behavior
4. Undocumented: No mention in the documentation, or it's too hard for me to find
*/
$('.form-group').removeClass('row')

View File

@ -0,0 +1,26 @@
.alert-debug {
background-color: #fff;
border-color: #d6e9c6;
color: #000; }
.alert-error {
background-color: #f2dede;
border-color: #eed3d7;
color: #b94a48; }
.navbar {
border-radius: 0px; }
@media (max-width: 47.9em) {
.navbar-nav .nav-item {
display: inline-block;
float: none;
width: 100%; }
.navbar-nav .nav-item + .nav-item {
margin-left: 0; }
.nav.navbar-nav.pull-xs-right {
float: none !important; } }
[hidden][style="display: block;"] {
display: block !important; }

View File

@ -0,0 +1,71 @@
// project specific CSS goes here
////////////////////////////////
//Variables//
////////////////////////////////
// Alert colors
$white: #fff;
$mint-green: #d6e9c6;
$black: #000;
$pink: #f2dede;
$dark-pink: #eed3d7;
$red: #b94a48;
////////////////////////////////
//Alerts//
////////////////////////////////
// bootstrap alert CSS, translated to the django-standard levels of
// debug, info, success, warning, error
.alert-debug {
background-color: $white;
border-color: $mint-green;
color: $black;
}
.alert-error {
background-color: $pink;
border-color: $dark-pink;
color: $red;
}
////////////////////////////////
//Navbar//
////////////////////////////////
// This is a fix for the bootstrap4 alpha release
.navbar {
border-radius: 0px;
}
@media (max-width: 47.9em) {
.navbar-nav .nav-item {
display: inline-block;
float: none;
width: 100%;
}
.navbar-nav .nav-item + .nav-item {
margin-left: 0;
}
.nav.navbar-nav.pull-xs-right {
float: none !important;
}
}
////////////////////////////////
//Django Toolbar//
////////////////////////////////
// Display django-debug-toolbar.
// See https://github.com/django-debug-toolbar/django-debug-toolbar/issues/742
// and https://github.com/pydanny/cookiecutter-django/issues/317
[hidden][style="display: block;"] {
display: block !important;
}

View File

@ -20,7 +20,7 @@
<!-- Your stuff: Third-party CSS libraries go here --> <!-- Your stuff: Third-party CSS libraries go here -->
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress css %}{% endraw %}{% endif %}{% raw %} {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress css %}{% endraw %}{% endif %}{% raw %}
<!-- This file stores project-specific CSS --> <!-- This file stores project-specific CSS -->
<link href="{% static 'css/project.css' %}" rel="stylesheet"> <link href="{% static 'build/styles.min.css' %}" rel="stylesheet"/>
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %} {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %}
{% endblock %} {% endblock %}
@ -88,6 +88,13 @@
================================================== --> ================================================== -->
<!-- Placed at the end of the document so the pages load faster --> <!-- Placed at the end of the document so the pages load faster -->
{% block javascript %} {% block javascript %}
<!-- BrowserSync debug-only support -->
{% if debug %}
<script id="__bs_script__">//<![CDATA[
document.write('<script async src=\'http://HOST:3000/browser-sync/browser-sync-client.js?v=2.18.8\'><\/script>'.replace('HOST', location.hostname))
//]]></script>
{% endif %}
<!-- Required by Bootstrap v4 Alpha 4 --> <!-- Required by Bootstrap v4 Alpha 4 -->
<script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script> <script src="https://code.jquery.com/jquery-3.1.1.slim.min.js" integrity="sha384-A7FZj7v+d/sdmMqp/nOQwliLvUsJfDHW+k9Omg/a/EheAdgtzNs3hpfag6Ed950n" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
@ -97,7 +104,7 @@
<!-- place project specific Javascript in this file --> <!-- place project specific Javascript in this file -->
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress js %}{% endraw %}{% endif %}{% raw %} {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress js %}{% endraw %}{% endif %}{% raw %}
<script src="{% static 'js/project.js' %}"></script> <script src="{% static 'build/scripts.min.js' %}"></script>
{% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %} {% endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %}
{% endblock javascript %} {% endblock javascript %}