Unify compressor, gulp and custom bootstrap options (#3535)

This commit is contained in:
Bruno Alla 2022-03-20 15:00:40 +00:00 committed by GitHub
parent bd12be3b38
commit ab4a32d558
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 78 additions and 101 deletions

View File

@ -50,7 +50,7 @@ jobs:
- name: Basic
args: ""
- name: Extended
args: "use_celery=y use_drf=y js_task_runner=Gulp"
args: "use_celery=y use_drf=y frontend_pipeline=Gulp"
name: "${{ matrix.script.name }} Docker"
runs-on: ubuntu-latest
@ -75,9 +75,9 @@ jobs:
matrix:
script:
- name: With Celery
args: "use_celery=y use_compressor=y"
args: "use_celery=y frontend_pipeline='Django Compressor'"
- name: With Gulp
args: "js_task_runner=Gulp custom_bootstrap_compilation=y"
args: "frontend_pipeline='Gulp'"
name: "${{ matrix.script.name }} Bare metal"
runs-on: ubuntu-latest

View File

@ -127,10 +127,6 @@ Answer the prompts with your own desired [options](http://cookiecutter-django.re
4 - 11.14
5 - 10.19
Choose from 1, 2, 3, 4, 5 [1]: 1
Select js_task_runner:
1 - None
2 - Gulp
Choose from 1, 2 [1]: 1
Select cloud_provider:
1 - AWS
2 - GCP
@ -149,8 +145,12 @@ Answer the prompts with your own desired [options](http://cookiecutter-django.re
Choose from 1, 2, 3, 4, 5, 6, 7, 8, 9 [1]: 1
use_async [n]: n
use_drf [n]: y
custom_bootstrap_compilation [n]: n
use_compressor [n]: n
Select frontend_pipeline:
1 - None
2 - Django Compressor
3 - Gulp
4 - Gulp with custom Bootstrap
Choose from 1, 2, 3, 4 [1]: 1
use_celery [n]: y
use_mailhog [n]: n
use_sentry [n]: y

View File

@ -24,10 +24,6 @@
"11.14",
"10.19"
],
"js_task_runner": [
"None",
"Gulp"
],
"cloud_provider": [
"AWS",
"GCP",
@ -46,8 +42,11 @@
],
"use_async": "n",
"use_drf": "n",
"custom_bootstrap_compilation": "n",
"use_compressor": "n",
"frontend_pipeline": [
"None",
"Django Compressor",
"Gulp"
],
"use_celery": "n",
"use_mailhog": "n",
"use_sentry": "n",

View File

@ -112,7 +112,7 @@ Or add the DSN for your account, if you already have one:
Gulp & Bootstrap compilation
++++++++++++++++++++++++++++
If you've opted for a custom bootstrap build, you'll most likely need to setup
If you've opted for Gulp, you'll most likely need to setup
your app to use `multiple buildpacks`_: one for Python & one for Node.js:
.. code-block:: bash

View File

@ -155,7 +155,7 @@ To run Celery locally, make sure redis-server is installed (instructions are ava
Sass Compilation & Live Reloading
---------------------------------
If you've opted for Gulp as JS task runner, the project comes configured with `Sass`_ compilation and `live reloading`_. As you change you Sass/JS source files, the task runner will automatically rebuild the corresponding CSS and JS assets and reload them in your browser without refreshing the page.
If you've opted for Gulp as front-end pipeline, the project comes configured with `Sass`_ compilation and `live reloading`_. As you change you Sass/JS source files, the task runner will automatically rebuild the corresponding CSS and JS assets and reload them in your browser without refreshing the page.
#. Make sure that `Node.js`_ v16 is installed on your machine.
#. In the project root, install the JS dependencies with::

View File

@ -61,12 +61,6 @@ postgresql_version:
4. 11.14
5. 10.19
js_task_runner:
Select a JavaScript task runner. The choices are:
1. None
2. Gulp_
cloud_provider:
Select a cloud provider for static & media files. The choices are:
@ -95,13 +89,12 @@ use_async:
use_drf:
Indicates whether the project should be configured to use `Django Rest Framework`_.
custom_bootstrap_compilation:
Indicates whether the project should support Bootstrap recompilation
via the selected JavaScript task runner's task. This can be useful
for real-time Bootstrap variable alteration.
frontend_pipeline:
Select a pipeline to compile and optimise frontend assets (JS, CSS, ...):
use_compressor:
Indicates whether the project should be configured to use `Django Compressor`_.
1. None
2. `Django Compressor`_
3. `Gulp`_: support Bootstrap recompilation with real-time variables alteration.
use_celery:
Indicates whether the project should be configured to use Celery_.

View File

@ -10,7 +10,6 @@ TODO: restrict Cookiecutter Django project initialization to
"""
from __future__ import print_function
import json
import os
import random
import shutil
@ -92,6 +91,11 @@ def remove_gulp_files():
file_names = ["gulpfile.js"]
for file_name in file_names:
os.remove(file_name)
remove_sass_files()
def remove_sass_files():
shutil.rmtree(os.path.join("{{cookiecutter.project_slug}}", "static", "sass"))
def remove_packagejson_file():
@ -100,16 +104,6 @@ def remove_packagejson_file():
os.remove(file_name)
def remove_bootstrap_packages():
with open("package.json", mode="r") as fd:
content = json.load(fd)
for package_name in ["bootstrap", "gulp-concat", "@popperjs/core"]:
content["devDependencies"].pop(package_name)
with open("package.json", mode="w") as fd:
json.dump(content, fd, ensure_ascii=False, indent=2)
fd.write("\n")
def remove_celery_files():
file_names = [
os.path.join("config", "celery_app.py"),
@ -363,13 +357,13 @@ def main():
if (
"{{ cookiecutter.use_docker }}".lower() == "y"
and "{{ cookiecutter.cloud_provider}}".lower() != "aws"
and "{{ cookiecutter.cloud_provider}}" != "AWS"
):
remove_aws_dockerfile()
if "{{ cookiecutter.use_heroku }}".lower() == "n":
remove_heroku_files()
elif "{{ cookiecutter.use_compressor }}".lower() == "n":
elif "{{ cookiecutter.frontend_pipeline }}" != "Django Compressor":
remove_heroku_build_hooks()
if (
@ -389,15 +383,13 @@ def main():
if "{{ cookiecutter.keep_local_envs_in_vcs }}".lower() == "y":
append_to_gitignore_file("!.envs/.local/")
if "{{ cookiecutter.js_task_runner}}".lower() == "none":
if "{{ cookiecutter.frontend_pipeline }}" != "Gulp":
remove_gulp_files()
remove_packagejson_file()
if "{{ cookiecutter.use_docker }}".lower() == "y":
remove_node_dockerfile()
elif "{{ cookiecutter.custom_bootstrap_compilation }}" == "n":
remove_bootstrap_packages()
if "{{ cookiecutter.cloud_provider}}".lower() == "none":
if "{{ cookiecutter.cloud_provider}}" == "None":
print(
WARNING + "You chose not to use a cloud provider, "
"media files won't be served in production." + TERMINATOR
@ -409,13 +401,13 @@ def main():
if "{{ cookiecutter.use_docker }}".lower() == "y":
remove_celery_compose_dirs()
if "{{ cookiecutter.ci_tool }}".lower() != "travis":
if "{{ cookiecutter.ci_tool }}" != "Travis":
remove_dottravisyml_file()
if "{{ cookiecutter.ci_tool }}".lower() != "gitlab":
if "{{ cookiecutter.ci_tool }}" != "Gitlab":
remove_dotgitlabciyml_file()
if "{{ cookiecutter.ci_tool }}".lower() != "github":
if "{{ cookiecutter.ci_tool }}" != "Github":
remove_dotgithub_folder()
if "{{ cookiecutter.use_drf }}".lower() == "n":

View File

@ -87,12 +87,9 @@ SUPPORTED_COMBINATIONS = [
{"use_async": "n"},
{"use_drf": "y"},
{"use_drf": "n"},
{"js_task_runner": "None"},
{"js_task_runner": "Gulp"},
{"custom_bootstrap_compilation": "y"},
{"custom_bootstrap_compilation": "n"},
{"use_compressor": "y"},
{"use_compressor": "n"},
{"frontend_pipeline": "None"},
{"frontend_pipeline": "django-compressor"},
{"frontend_pipeline": "Gulp"},
{"use_celery": "y"},
{"use_celery": "n"},
{"use_mailhog": "y"},

View File

@ -82,7 +82,7 @@ updates:
schedule:
interval: "daily"
{%- if cookiecutter.js_task_runner != "None" %}
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
# Enable version updates for javascript/npm
- package-ecosystem: "npm"

View File

@ -338,7 +338,7 @@ MailHog
.ipython/
{%- endif %}
{%- if cookiecutter.js_task_runner == 'Gulp' %}
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
project.css
project.min.css
vendors.js

View File

@ -10,7 +10,7 @@
<option value="celeryworker"/>
<option value="celerybeat"/>
{%- endif %}
{%- if cookiecutter.js_task_runner == 'Gulp' %}
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
<option value="node"/>
{%- endif %}
</list>

View File

@ -13,7 +13,7 @@
</facet>
</component>
<component name="NewModuleRootManager">
{% if cookiecutter.js_task_runner != 'None' %}
{% if cookiecutter.frontend_pipeline == 'Gulp' %}
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/node_modules" />
</content>

View File

@ -128,7 +128,7 @@ See detailed [cookiecutter-django Heroku documentation](http://cookiecutter-djan
See detailed [cookiecutter-django Docker documentation](http://cookiecutter-django.readthedocs.io/en/latest/deployment-with-docker.html).
{%- endif %}
{%- if cookiecutter.custom_bootstrap_compilation == "y" %}
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
### Custom Bootstrap Compilation
The generated CSS is set up with automatic Bootstrap recompilation with variables of your choice.
@ -136,8 +136,5 @@ Bootstrap v5 is installed using npm and customised by tweaking your variables in
You can find a list of available variables [in the bootstrap source](https://github.com/twbs/bootstrap/blob/main/scss/_variables.scss), or get explanations on them in the [Bootstrap docs](https://getbootstrap.com/docs/5.1/customize/sass/).
{%- 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 %}
{%- endif %}

View File

@ -1,6 +1,6 @@
ARG PYTHON_VERSION=3.9-slim-bullseye
{% if cookiecutter.js_task_runner == 'Gulp' -%}
{% if cookiecutter.frontend_pipeline == 'Gulp' -%}
FROM node:16-bullseye-slim as client-builder
ARG APP_HOME=/app
@ -99,7 +99,7 @@ RUN chmod +x /start-flower
# copy application code to WORKDIR
{%- if cookiecutter.js_task_runner == 'Gulp' %}
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
COPY --from=client-builder --chown=django:django ${APP_HOME} ${APP_HOME}
{% else %}
COPY --chown=django:django . ${APP_HOME}

View File

@ -6,7 +6,7 @@ set -o nounset
python /app/manage.py collectstatic --noinput
{% if cookiecutter.use_whitenoise == 'y' and cookiecutter.use_compressor == 'y' %}
{% if cookiecutter.use_whitenoise == 'y' and cookiecutter.frontend_pipeline == 'Django Compressor' %}
compress_enabled() {
python << END
import sys

View File

@ -316,7 +316,7 @@ ACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSignup
SOCIALACCOUNT_ADAPTER = "{{cookiecutter.project_slug}}.users.adapters.SocialAccountAdapter"
# https://django-allauth.readthedocs.io/en/latest/forms.html
SOCIALACCOUNT_FORMS = {"signup": "{{cookiecutter.project_slug}}.users.forms.UserSocialSignupForm"}
{% if cookiecutter.use_compressor == 'y' -%}
{% if cookiecutter.frontend_pipeline == 'Django Compressor' -%}
# django-compressor
# ------------------------------------------------------------------------------
# https://django-compressor.readthedocs.io/en/latest/quickstart/#installation

View File

@ -69,7 +69,7 @@ if env("USE_DOCKER") == "yes":
hostname, _, ips = socket.gethostbyname_ex(socket.gethostname())
INTERNAL_IPS += [".".join(ip.split(".")[:-1] + ["1"]) for ip in ips]
{%- if cookiecutter.js_task_runner == 'Gulp' %}
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
try:
_, _, ips = socket.gethostbyname_ex("node")
INTERNAL_IPS.extend(ips)

View File

@ -218,7 +218,7 @@ EMAIL_BACKEND = "django.core.mail.backends.smtp.EmailBackend"
ANYMAIL = {}
{%- endif %}
{% if cookiecutter.use_compressor == 'y' -%}
{% if cookiecutter.frontend_pipeline == 'Django Compressor' -%}
# django-compressor
# ------------------------------------------------------------------------------
# https://django-compressor.readthedocs.io/en/latest/settings/#django.conf.settings.COMPRESS_ENABLED

View File

@ -9,9 +9,7 @@ const pjson = require('./package.json')
// Plugins
const autoprefixer = require('autoprefixer')
const browserSync = require('browser-sync').create()
{% if cookiecutter.custom_bootstrap_compilation == 'y' %}
const concat = require('gulp-concat')
{% endif %}
const cssnano = require ('cssnano')
const imagemin = require('gulp-imagemin')
const pixrem = require('pixrem')
@ -29,13 +27,11 @@ function pathsConfig(appName) {
const vendorsRoot = 'node_modules'
return {
{%- if cookiecutter.custom_bootstrap_compilation == 'y' %}
bootstrapSass: `${vendorsRoot}/bootstrap/scss`,
vendorsJs: [
`${vendorsRoot}/@popperjs/core/dist/umd/popper.js`,
`${vendorsRoot}/bootstrap/dist/js/bootstrap.js`,
],
{%- endif %}
app: this.app,
templates: `${this.app}/templates`,
css: `${this.app}/static/css`,
@ -66,9 +62,7 @@ function styles() {
return src(`${paths.sass}/project.scss`)
.pipe(sass({
includePaths: [
{%- if cookiecutter.custom_bootstrap_compilation == 'y' %}
paths.bootstrapSass,
{%- endif %}
paths.sass
]
}).on('error', sass.logError))
@ -89,7 +83,6 @@ function scripts() {
.pipe(dest(paths.js))
}
{%- if cookiecutter.custom_bootstrap_compilation == 'y' %}
// Vendor Javascript minification
function vendorScripts() {
return src(paths.vendorsJs)
@ -100,7 +93,6 @@ function vendorScripts() {
.pipe(rename({ suffix: '.min' }))
.pipe(dest(paths.js))
}
{%- endif %}
// Image compression
function imgCompression() {
@ -173,7 +165,7 @@ function watchPaths() {
const generateAssets = parallel(
styles,
scripts,
{%- if cookiecutter.custom_bootstrap_compilation == 'y' %}vendorScripts,{% endif %}
vendorScripts,
imgCompression
)

View File

@ -107,7 +107,7 @@ services:
command: /start-flower
{%- endif %}
{%- if cookiecutter.js_task_runner == 'Gulp' %}
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
node:
build:

View File

@ -1,6 +1,6 @@
[pytest]
addopts = --ds=config.settings.test --reuse-db
python_files = tests.py test_*.py
{%- if cookiecutter.js_task_runner != 'None' %}
{%- if cookiecutter.frontend_pipeline == 'Gulp' %}
norecursedirs = node_modules
{%- endif %}

View File

@ -1,7 +1,7 @@
pytz==2021.3 # https://github.com/stub42/pytz
python-slugify==6.1.1 # https://github.com/un33k/python-slugify
Pillow==9.0.1 # https://github.com/python-pillow/Pillow
{%- if cookiecutter.use_compressor == "y" %}
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
{%- if cookiecutter.windows == 'y' and cookiecutter.use_docker == 'n' %}
rcssmin==1.1.0 --install-option="--without-c-extensions" # https://github.com/ndparker/rcssmin
{%- else %}
@ -35,11 +35,11 @@ django-model-utils==4.2.0 # https://github.com/jazzband/django-model-utils
django-allauth==0.49.0 # https://github.com/pennersr/django-allauth
django-crispy-forms==1.14.0 # https://github.com/django-crispy-forms/django-crispy-forms
crispy-bootstrap5==0.6 # https://github.com/django-crispy-forms/crispy-bootstrap5
{%- if cookiecutter.use_compressor == "y" %}
{%- if cookiecutter.frontend_pipeline == 'Django Compressor' %}
django-compressor==3.1 # https://github.com/django-compressor/django-compressor
{%- endif %}
django-redis==5.2.0 # https://github.com/jazzband/django-redis
{%- if cookiecutter.use_drf == "y" %}
{%- if cookiecutter.use_drf == 'y' %}
# Django REST Framework
djangorestframework==3.13.1 # https://github.com/encode/django-rest-framework
django-cors-headers==3.11.0 # https://github.com/adamchainz/django-cors-headers

View File

@ -1,8 +1,5 @@
{% if cookiecutter.custom_bootstrap_compilation == 'y' %}
@import "custom_bootstrap_vars";
@import "bootstrap";
{% endif %}
// project specific CSS goes here

View File

@ -1,4 +1,4 @@
{% raw %}{% load static i18n {% endraw %}{% if cookiecutter.use_compressor == "y" %}compress{% endif %}{% raw %}%}<!DOCTYPE html>
{% raw %}{% load static i18n {% endraw %}{% if cookiecutter.frontend_pipeline == 'Django Compressor' %}compress{% endif %}{% raw %}%}<!DOCTYPE html>
{% get_current_language as LANGUAGE_CODE %}
<html lang="{{ LANGUAGE_CODE }}">
<head>
@ -12,30 +12,34 @@
<link rel="icon" href="{% static 'images/favicons/favicon.ico' %}">
{% block css %}
{%- endraw %}{% if cookiecutter.custom_bootstrap_compilation == "n" %}{% raw %}
{%- endraw %}
{%- if cookiecutter.frontend_pipeline != 'Gulp' %}
{%- raw %}
<!-- Latest compiled and minified Bootstrap CSS -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/css/bootstrap.min.css" integrity="sha512-GQGU0fMMi238uA+a/bdWJfpUGKUkBdgfFdgBm72SUQ6BeyWjoY/ton0tEjH+OSH9iP4Dfh+7HM0I9f5eR0L/4w==" crossorigin="anonymous" referrerpolicy="no-referrer" />
{%- endraw %}{% endif %}{% raw %}
{%- endraw %}
{%- endif %}
{%- raw %}
<!-- Your stuff: Third-party CSS libraries go here -->
{%- endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress css %}{% endraw %}{% endif %}{% raw %}
<!-- This file stores project-specific CSS -->
{%- endraw %}{% if cookiecutter.js_task_runner == "Gulp" and cookiecutter.use_compressor == "n" %}{% raw %}
<link href="{% static 'css/project.min.css' %}" rel="stylesheet">
{%- endraw %}{% else %}{% raw %}
{%- endraw %}{% if cookiecutter.frontend_pipeline == 'None' %}{% raw %}
<link href="{% static 'css/project.css' %}" rel="stylesheet">
{%- endraw %}{% elif cookiecutter.frontend_pipeline == 'Django Compressor' %}{% raw %}
{% compress css %}
<link href="{% static 'css/project.css' %}" rel="stylesheet">
{% endcompress %}
{%- endraw %}{% elif cookiecutter.frontend_pipeline == 'Gulp' %}{% raw %}
<link href="{% static 'css/project.min.css' %}" rel="stylesheet">
{%- endraw %}{% endif %}{% raw %}
{%- endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %}
{% endblock %}
<!-- Le javascript
================================================== -->
{# Placed at the top of the document so pages load faster with defer #}
{% block javascript %}
{%- endraw %}{% if cookiecutter.custom_bootstrap_compilation == "y" and cookiecutter.js_task_runner == "Gulp" %}{% raw %}
{%- endraw %}{% if cookiecutter.frontend_pipeline == 'Gulp' %}{% raw %}
<!-- Vendor dependencies bundled as one file-->
{%- endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress js %}{% endraw %}{% endif %}{% raw %}
<script defer src="{% static 'js/vendors.js' %}"></script>
{%- endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %}
<script defer src="{% static 'js/vendors.min.js' %}"></script>
{%- endraw %}{% else %}{% raw %}
<!-- Bootstrap JS -->
<script defer src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap/5.1.3/js/bootstrap.min.js" integrity="sha512-OvBgP9A2JBgiRad/mM36mkzXSXaJE9BEIENnVEmeZdITvwT09xnxLtT4twkCa8m/loMbPHsvPl0T8lRGVBwjlQ==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
@ -43,9 +47,15 @@
{%- endraw %}{% endif %}{% raw %}
<!-- place project specific Javascript in this file -->
{%- endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% compress js %}{% endraw %}{% endif %}{% raw %}
{%- endraw %}{% if cookiecutter.frontend_pipeline == 'None' %}{% raw %}
<script defer src="{% static 'js/project.js' %}"></script>
{%- endraw %}{% if cookiecutter.use_compressor == "y" %}{% raw %}{% endcompress %}{% endraw %}{% endif %}{% raw %}
{%- endraw %}{% elif cookiecutter.frontend_pipeline == 'Django Compressor' %}{% raw %}
{% compress js %}
<script defer src="{% static 'js/project.js' %}"></script>
{% endcompress %}
{%- endraw %}{% elif cookiecutter.frontend_pipeline == 'Gulp' %}{% raw %}
<script defer src="{% static 'js/project.min.js' %}"></script>
{%- endraw %}{% endif %}{% raw %}
{% endblock javascript %}