Skip to content

Commit

Permalink
Merge pull request #356 from datamade/feature/webpack
Browse files Browse the repository at this point in the history
replace django compressor with webpack in the django cookiecutter template
  • Loading branch information
smcalilly authored Jan 25, 2024
2 parents 4a90e4a + 598cf77 commit 4a24569
Show file tree
Hide file tree
Showing 10 changed files with 168 additions and 48 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,8 @@ venv.bak/
# Compiled JavaScript
node_modules/
!{{cookiecutter.module_name}}/static/js/lib/
assets/*
!assets/.gitkeep

# macOS
.DS_Store
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,12 @@ RUN npm install
# the container.
COPY . /app

# Build static bundles with Webpack
RUN npm run build

# Add a bogus env var for the Django secret key in order to allow us to run
# the 'collectstatic' management command
ENV DJANGO_SECRET_KEY 'foobar'

# Sets Debug to False to make sure that Django compressor can run.
# Unless overridden in docker-compose.yml or .env locally or config variables
# in Heroku, this sets the environment to production mode
ENV DJANGO_DEBUG 'False'

# Build static files into the container
RUN python manage.py collectstatic --noinput
RUN python manage.py compress
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
FROM node:18 AS webpack

# Give ourselves some credit
LABEL maintainer "DataMade <[email protected]>"

# Inside the container, create an app directory and switch into it
RUN mkdir /app
WORKDIR /app

# Install Node requirements
COPY ./package.json /app/package.json
RUN npm install

FROM python:3.10 AS app

LABEL maintainer "DataMade <[email protected]>"

RUN curl -sL https://deb.nodesource.com/setup_18.x | bash -

RUN apt-get install -y --no-install-recommends postgresql-client nodejs{% if cookiecutter.postgis == 'True' %} gdal-bin{% endif %}

RUN mkdir /app
WORKDIR /app

COPY ./requirements.txt /app/requirements.txt
RUN pip install --no-cache-dir -r requirements.txt

COPY --from=webpack /app/node_modules /app/node_modules

COPY . /app

# Add a bogus env var for the Django secret key in order to allow us to run
# the 'collectstatic' management command
ENV DJANGO_SECRET_KEY 'foobar'
RUN python manage.py collectstatic --noinput
Empty file.
Original file line number Diff line number Diff line change
@@ -1,16 +1,32 @@
version: '2.4'

services:
webpack:
# Runs the webpack server for local development.
build:
context: .
dockerfile: Dockerfile.dev
target: webpack
stdin_open: true
ports:
- 3000:3000
volumes:
- .:/app
- {{cookiecutter.app_name}}-node-modules:/app/node_modules
command: npm run serve
app:
# As soon as possible, get an image of your app on the github container registry
# and use that image for local development. This will avoid drift between containers
# on different machines.
#
#
# When that is ready, uncomment the next line, and delete the following two lines
# and commit those changes to the repository.
# image: ghcr.io/datamade/{{cookiecutter.app_name}}:latest
image: {{cookiecutter.app_name}}
build: .
build:
context: .
dockerfile: Dockerfile.dev
target: app
container_name: {{cookiecutter.app_name}}
# Allow container to be attached to, e.g., to access the pdb shell
stdin_open: true
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,26 @@
"@typescript-eslint/eslint-plugin": "^5.53.0",
"@typescript-eslint/parser": "^5.53.0",
"@babel/eslint-parser": "^7.19.1",
"babel-loader": "^9.1.0",
"browserify-css": "^0.15.0",
"css-loader": "^6.7.2",
"eslint": "^8.34.0",
"eslint-config-prettier": "^8.7.0",
"eslint-config-react-app": "^7.0.1",
"eslint-plugin-flowtype": "^8.0.3",
"eslint-plugin-import": "^2.27.5",
"eslint-plugin-jsx-a11y": "^6.7.1",
"eslint-plugin-react": "^7.32.2",
"eslint-plugin-react-hooks": "^4.6.0"
"eslint-plugin-react-hooks": "^4.6.0",
"style-loader": "^3.3.1",
"webpack": "^5.75.0",
"webpack-bundle-tracker": "^1.7.0",
"webpack-cli": "^5.0.0",
"webpack-dev-server": "^4.11.1"
},
"scripts": {
"develop": "sass --watch /app/{{ cookiecutter.module_name }}/static/scss/custom.scss:/app/{{ cookiecutter.module_name }}/static/css/bootstrap.custom.css"
"develop": "sass --watch /app/{{ cookiecutter.module_name }}/static/scss/custom.scss:/app/{{ cookiecutter.module_name }}/static/css/bootstrap.custom.css",
"build": "webpack --mode=production",
"serve": "webpack-dev-server --config webpack.config.js --mode=development --host 0.0.0.0 --hot --open"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ psycopg2
gunicorn
dj-database-url
whitenoise
django-compressor
django-webpack-loader
sentry-sdk

# Testing requirements
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
const path = require("path")
const webpack = require("webpack") // eslint-disable-line no-unused-vars
const BundleTracker = require("webpack-bundle-tracker")

const config = {
context: __dirname,
entry: {
base: "./{{cookiecutter.module_name}}/static/js/base.js",
},
output: {
path: path.resolve(__dirname, "assets/bundles/"),
filename: "[name]-[hash].js",
chunkFilename: "[name]-[hash].js",
},
plugins: [
new BundleTracker({
path: __dirname,
filename: "webpack-stats.json"
})
],
devServer: {
watchFiles: ["{{cookiecutter.app_name}}/static/**/*.js"],
host: "0.0.0.0",
port: 3000,
compress: false,
allowedHosts: ["localhost"],
},
watchOptions: {
poll: 1000,
},
resolve: {
extensions: [".js", ".jsx", ".geojson"],
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: "babel-loader",
options: {
presets: ["@babel/preset-env", "@babel/preset-react"]
},
},
{
test: /\.geojson$/,
type: "json",
},
{
test: /\.css$/i,
use: [
// Creates `style` nodes from JS strings
"style-loader",
// Translates CSS into CommonJS
"css-loader",
],
},
{
test: /\.(jpg|png|mp4)$/,
use: {
loader: "url-loader",
},
},
],
},
}

module.exports = (env, argv) => {
/*
* /app/webpack-stats.json is the roadmap for the assorted chunks of JS
* produced by Webpack. During local development, the Webpack server
* serves our bundles. In production, Django should look in
* /app/static/bundles for bundles.
*/
if (argv.mode === "development") {
config.output.publicPath = "http://localhost:3000/static/bundles/"
}

if (argv.mode === "production") {
config.output.publicPath = "/static/bundles/"
}

return config
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'compressor',
"webpack_loader",
'{{cookiecutter.module_name}}'
]

Expand Down Expand Up @@ -145,43 +145,24 @@

STATIC_URL = '/static/'
STATIC_ROOT = '/static'
STATICFILES_DIRS = (os.path.join(BASE_DIR, "assets"),)
STATICFILES_STORAGE = os.getenv(
'DJANGO_STATICFILES_STORAGE',
'whitenoise.storage.CompressedManifestStaticFilesStorage'
)
STATICFILES_FINDERS = (
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'compressor.finders.CompressorFinder',
)

# Django Compressor configs
# This array determines which command django-compressor will run for each
# script type (<script type="module"> for vanilla JavaScript, <script
# type="text/jsx"> for React). CLI options are _combined_ with the options in
# the package Babel config, babel.config.json. By default, we use the
# @babel/preset-env preset. Need to transpile browser incompatible plugins?
# Add them to the "only" array in babel.config.json, as documented in the
# README under "Ensuring browser compatibility".
COMPRESS_PRECOMPILERS = (
(
"module",
"export NODE_PATH=/app/node_modules && npx browserify {infile} -t \
[ babelify --global --presets [ @babel/preset-env ] ] > {outfile}",
),
(
"text/jsx",
"export NODE_PATH=/app/node_modules && npx browserify {infile} -t \
[ babelify --global --presets [ @babel/preset-env @babel/preset-react ] ] > {outfile}",
),
)

COMPRESS_OUTPUT_DIR = 'compressor'

COMPRESS_ENABLED = True

# Enable offline compression in production only
COMPRESS_OFFLINE = not DEBUG
WEBPACK_LOADER = {
"DEFAULT": {
"CACHE": not DEBUG,
"STATS_FILE": os.path.join(BASE_DIR, "webpack-stats.json"),
"POLL_INTERVAL": not DEBUG,
"IGNORE": [r".+\.hot-update.js", r".+\.map"],
}
}

# Enforce SSL in production
if DEBUG is False:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,9 @@ <h1 class="mb-3">{% endraw %}{{cookiecutter.app_verbose_name}}{% raw %}</h1>
{% endblock %}

{% block extra_js %}
{% load compress %}
<!-- Example of how to use Django Compressor -->
{% compress js %}
<script type="module" src="{% static 'js/base.js' %}"></script>
<script type="module">
console.log('Hello, inline world!')
</script>
{% endcompress %}

<!-- Example of how to load JavaScript -->
{% load render_bundle from webpack_loader %}
{% render_bundle 'base' js %}

{% endblock %}{% endraw %}

0 comments on commit 4a24569

Please sign in to comment.