Remove deprecated flask-webpack library

master
James Curtin 5 years ago committed by James Curtin
parent 1f5ea80d0c
commit 3e53bdb824
  1. 1
      {{cookiecutter.app_name}}/.env.example
  2. 1
      {{cookiecutter.app_name}}/.gitignore
  3. 4
      {{cookiecutter.app_name}}/Pipfile
  4. 22
      {{cookiecutter.app_name}}/README.rst
  5. 12
      {{cookiecutter.app_name}}/package.json
  6. 4
      {{cookiecutter.app_name}}/requirements/prod.txt
  7. 1
      {{cookiecutter.app_name}}/tests/settings.py
  8. 44
      {{cookiecutter.app_name}}/webpack.config.js
  9. 4
      {{cookiecutter.app_name}}/{{cookiecutter.app_name}}/app.py
  10. 4
      {{cookiecutter.app_name}}/{{cookiecutter.app_name}}/extensions.py
  11. 2
      {{cookiecutter.app_name}}/{{cookiecutter.app_name}}/settings.py
  12. 87
      {{cookiecutter.app_name}}/{{cookiecutter.app_name}}/templates/layout.html

@ -6,3 +6,4 @@ DATABASE_URL=sqlite:////tmp/dev.db
GUNICORN_WORKERS=1 GUNICORN_WORKERS=1
LOG_LEVEL=debug LOG_LEVEL=debug
SECRET_KEY=not-so-secret SECRET_KEY=not-so-secret
SEND_FILE_MAX_AGE_DEFAULT=0 # In production, set to a higher number, like 31556926

@ -50,7 +50,6 @@ env/
# webpack-built files # webpack-built files
/{{cookiecutter.app_name}}/static/build/ /{{cookiecutter.app_name}}/static/build/
/{{cookiecutter.app_name}}/webpack/manifest.json
# Configuration # Configuration
.env .env

@ -26,8 +26,8 @@ gevent = "==1.4.0"
gunicorn = ">=19.1.1" gunicorn = ">=19.1.1"
supervisor = "==4.1.0" supervisor = "==4.1.0"
# Webpack # Flask Static Digest
flask-webpack = "==0.1.0" Flask-Static-Digest = "==0.1.2"
# Auth # Auth
Flask-Login = "==0.4.1" Flask-Login = "==0.4.1"

@ -98,7 +98,7 @@ Make sure folder `migrations/versions` is not empty.
Docker Docker
------ ------
This app can be run completely using ``Docker`` and ``docker-compose``. Before starting, make sure to create a new copy of ``.env.example`` called ``.env``. You will need to start the development version of the app at least once before running other Docker commands, as starting the dev app bootstraps a necessary file, ``webpack/manifest.json``. This app can be run completely using ``Docker`` and ``docker-compose``. Before starting, make sure to create a new copy of ``.env.example`` called ``.env``.
There are three main services: There are three main services:
@ -128,22 +128,20 @@ Asset Management
Files placed inside the ``assets`` directory and its subdirectories Files placed inside the ``assets`` directory and its subdirectories
(excluding ``js`` and ``css``) will be copied by webpack's (excluding ``js`` and ``css``) will be copied by webpack's
``file-loader`` into the ``static/build`` directory, with hashes of ``file-loader`` into the ``static/build`` directory. In production, the plugin
their contents appended to their names. For instance, if you have the ``Flask-Static-Digest`` zips the webpack content and tags them with a MD5 hash.
file ``assets/img/favicon.ico``, this will get copied into something As a result, you must use the ``static_url_for`` function when including static content,
like as it resolves the correct file name, including the MD5 hash.
``static/build/img/favicon.fec40b1d14528bf9179da3b6b78079ad.ico``. For example::
You can then put this line into your header::
<link rel="shortcut icon" href="{{ "{{" }}asset_url_for('img/favicon.ico') {{ "}}" }}"> <link rel="shortcut icon" href="{{ "{{" }}static_url_for('static', filename='build/img/favicon.ico') {{ "}}" }}">
to refer to it inside your HTML page. If all of your static files are If all of your static files are managed this way, then their filenames will change whenever their
managed this way, then their filenames will change whenever their
contents do, and you can ask Flask to tell web browsers that they contents do, and you can ask Flask to tell web browsers that they
should cache all your assets forever by including the following line should cache all your assets forever by including the following line
in your ``settings.py``:: in ``.env``::
SEND_FILE_MAX_AGE_DEFAULT = 31556926 # one year SEND_FILE_MAX_AGE_DEFAULT=31556926 # one year
{%- if cookiecutter.use_heroku == "yes" %} {%- if cookiecutter.use_heroku == "yes" %}

@ -3,12 +3,12 @@
"version": "1.0.0", "version": "1.0.0",
"description": "{{cookiecutter.project_short_description}}", "description": "{{cookiecutter.project_short_description}}",
"scripts": { "scripts": {
"build": "NODE_ENV=production webpack --progress --colors -p", "build": "NODE_ENV=production webpack --progress --colors -p && npm run flask-static-digest",
"start": "concurrently -n \"WEBPACK,FLASK\" -c \"bgBlue.bold,bgMagenta.bold\" \"npm run webpack-dev-server\" \"npm run flask-server\"", "start": "concurrently -n \"WEBPACK,FLASK\" -c \"bgBlue.bold,bgMagenta.bold\" \"npm run webpack-watch\" \"npm run flask-server\"",
"webpack-dev-server": "NODE_ENV=debug webpack-dev-server --host=0.0.0.0 --port 2992 --hot --inline", "webpack-watch": "NODE_ENV=debug webpack --mode development --watch",
"flask-server": "{% if cookiecutter.use_pipenv == 'yes' %}pipenv run {% endif %}flask run --host=0.0.0.0", "flask-server": "{% if cookiecutter.use_pipenv == 'yes' %}pipenv run {% endif %}flask run --host=0.0.0.0",
"lint": "eslint \"assets/js/*.js\"", "flask-static-digest": "{% if cookiecutter.use_pipenv == 'yes' %}pipenv run {% endif %}flask digest compile",
"postinstall": "npm run build" "lint": "eslint \"assets/js/*.js\""
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@ -42,13 +42,11 @@
"eslint": "^6.2.2", "eslint": "^6.2.2",
"file-loader": "^4.0.0", "file-loader": "^4.0.0",
"less-loader": "^5.0.0", "less-loader": "^5.0.0",
"manifest-revision-webpack-plugin": "^0.4.0",
"less": "^3.9.0", "less": "^3.9.0",
"mini-css-extract-plugin": "^0.8.0", "mini-css-extract-plugin": "^0.8.0",
"raw-loader": "^3.0.0", "raw-loader": "^3.0.0",
"url-loader": "^2.0.0", "url-loader": "^2.0.0",
"webpack-cli": "^3.3.2", "webpack-cli": "^3.3.2",
"webpack-dev-server": "^3.5.1",
"webpack": "^4.33.0" "webpack": "^4.33.0"
} }
} }

@ -22,8 +22,8 @@ gevent==1.4.0
gunicorn>=19.9.0 gunicorn>=19.9.0
supervisor==4.1.0 supervisor==4.1.0
# Webpack # Flask Static Digest
flask-webpack==0.1.0 Flask-Static-Digest==0.1.2
# Auth # Auth
Flask-Login==0.4.1 Flask-Login==0.4.1

@ -9,5 +9,4 @@ BCRYPT_LOG_ROUNDS = (
DEBUG_TB_ENABLED = False DEBUG_TB_ENABLED = False
CACHE_TYPE = "simple" # Can be "memcached", "redis", etc. CACHE_TYPE = "simple" # Can be "memcached", "redis", etc.
SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_TRACK_MODIFICATIONS = False
WEBPACK_MANIFEST_PATH = "webpack/manifest.json"
WTF_CSRF_ENABLED = False # Allows form testing WTF_CSRF_ENABLED = False # Allows form testing

@ -4,15 +4,11 @@ const webpack = require('webpack');
/* /*
* Webpack Plugins * Webpack Plugins
*/ */
const ManifestRevisionPlugin = require('manifest-revision-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// take debug mode from the environment // take debug mode from the environment
const debug = (process.env.NODE_ENV !== 'production'); const debug = (process.env.NODE_ENV !== 'production');
// Development asset host (webpack dev server)
const publicHost = debug ? 'http://0.0.0.0:2992' : '';
const rootAssetPath = path.join(__dirname, 'assets'); const rootAssetPath = path.join(__dirname, 'assets');
module.exports = { module.exports = {
@ -27,18 +23,15 @@ module.exports = {
], ],
}, },
output: { output: {
path: path.join(__dirname, '{{cookiecutter.app_name}}', 'static', 'build'), path: path.join(__dirname, "{{cookiecutter.app_name}}", "static", "build"),
publicPath: `${publicHost}/static/build/`, publicPath: "/static/build/",
filename: '[name].[hash].js', filename: "[name].js",
chunkFilename: '[id].[hash].js', chunkFilename: "[id].js"
}, },
resolve: { resolve: {
extensions: ['.js', '.jsx', '.css'], extensions: [".js", ".jsx", ".css"]
},
devtool: 'source-map',
devServer: {
headers: { 'Access-Control-Allow-Origin': '*' },
}, },
devtool: "source-map",
module: { module: {
rules: [ rules: [
{ {
@ -69,25 +62,24 @@ module.exports = {
{ test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader', options: { limit: 10000, mimetype: 'application/font-woff' } }, { test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, loader: 'url-loader', options: { limit: 10000, mimetype: 'application/font-woff' } },
{ {
test: /\.(ttf|eot|svg|png|jpe?g|gif|ico)(\?.*)?$/i, test: /\.(ttf|eot|svg|png|jpe?g|gif|ico)(\?.*)?$/i,
loader: `file-loader?context=${rootAssetPath}&name=[path][name].[hash].[ext]` loader: `file-loader?context=${rootAssetPath}&name=[path][name].[ext]`
}, },
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', query: { presets: ['env'], cacheDirectory: true } }, { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader', query: { presets: ['env'], cacheDirectory: true } },
], ],
}, },
plugins: [ plugins: [
new MiniCssExtractPlugin({ filename: '[name].[hash].css', }), new MiniCssExtractPlugin({ filename: "[name].css" }),
new webpack.ProvidePlugin({ $: 'jquery', jQuery: 'jquery' }), new webpack.ProvidePlugin({ $: "jquery", jQuery: "jquery" })
new ManifestRevisionPlugin(path.join(__dirname, '{{cookiecutter.app_name}}', 'webpack', 'manifest.json'), { ].concat(
rootAssetPath, debug
ignorePaths: ['/js', '/css'], ? []
extensionsRegex: /\.(ttf|eot|svg|png|jpe?g|gif|ico)$/i, : [
}),
].concat(debug ? [] : [
// production webpack plugins go here // production webpack plugins go here
new webpack.DefinePlugin({ new webpack.DefinePlugin({
'process.env': { "process.env": {
NODE_ENV: JSON.stringify('production'), NODE_ENV: JSON.stringify("production")
} }
}), })
]), ]
)
}; };

@ -12,9 +12,9 @@ from {{cookiecutter.app_name}}.extensions import (
csrf_protect, csrf_protect,
db, db,
debug_toolbar, debug_toolbar,
flask_static_digest,
login_manager, login_manager,
migrate, migrate,
webpack,
) )
@ -43,7 +43,7 @@ def register_extensions(app):
login_manager.init_app(app) login_manager.init_app(app)
debug_toolbar.init_app(app) debug_toolbar.init_app(app)
migrate.init_app(app, db) migrate.init_app(app, db)
webpack.init_app(app) flask_static_digest.init_app(app)
return None return None

@ -6,7 +6,7 @@ from flask_debugtoolbar import DebugToolbarExtension
from flask_login import LoginManager from flask_login import LoginManager
from flask_migrate import Migrate from flask_migrate import Migrate
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from flask_webpack import Webpack from flask_static_digest import FlaskStaticDigest
from flask_wtf.csrf import CSRFProtect from flask_wtf.csrf import CSRFProtect
bcrypt = Bcrypt() bcrypt = Bcrypt()
@ -16,4 +16,4 @@ db = SQLAlchemy()
migrate = Migrate() migrate = Migrate()
cache = Cache() cache = Cache()
debug_toolbar = DebugToolbarExtension() debug_toolbar = DebugToolbarExtension()
webpack = Webpack() flask_static_digest = FlaskStaticDigest()

@ -15,9 +15,9 @@ ENV = env.str("FLASK_ENV", default="production")
DEBUG = ENV == "development" DEBUG = ENV == "development"
SQLALCHEMY_DATABASE_URI = env.str("DATABASE_URL") SQLALCHEMY_DATABASE_URI = env.str("DATABASE_URL")
SECRET_KEY = env.str("SECRET_KEY") SECRET_KEY = env.str("SECRET_KEY")
SEND_FILE_MAX_AGE_DEFAULT = env.int("SEND_FILE_MAX_AGE_DEFAULT")
BCRYPT_LOG_ROUNDS = env.int("BCRYPT_LOG_ROUNDS", default=13) BCRYPT_LOG_ROUNDS = env.int("BCRYPT_LOG_ROUNDS", default=13)
DEBUG_TB_ENABLED = DEBUG DEBUG_TB_ENABLED = DEBUG
DEBUG_TB_INTERCEPT_REDIRECTS = False DEBUG_TB_INTERCEPT_REDIRECTS = False
CACHE_TYPE = "simple" # Can be "memcached", "redis", etc. CACHE_TYPE = "simple" # Can be "memcached", "redis", etc.
SQLALCHEMY_TRACK_MODIFICATIONS = False SQLALCHEMY_TRACK_MODIFICATIONS = False
WEBPACK_MANIFEST_PATH = "webpack/manifest.json"

@ -1,65 +1,70 @@
{% raw %} {% raw %}
<!doctype html> <!DOCTYPE html>
<!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ --> <!-- paulirish.com/2008/conditional-stylesheets-vs-css-hacks-answer-neither/ -->
<!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]--> <!--[if lt IE 7]> <html class="no-js lt-ie9 lt-ie8 lt-ie7" lang="en"> <![endif]-->
<!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]--> <!--[if IE 7]> <html class="no-js lt-ie9 lt-ie8" lang="en"> <![endif]-->
<!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]--> <!--[if IE 8]> <html class="no-js lt-ie9" lang="en"> <![endif]-->
<!--[if gt IE 8]><!--> <html class="no-js" lang="en"> <!--<![endif]--> <!--[if gt IE 8]><!-->
<head> <html class="no-js" lang="en">
<meta charset="utf-8"> <!--<![endif]-->
<head>
<meta charset="utf-8" />
<title>{% block page_title %} <title>
{% endraw %} {% block page_title %} {% endraw %}
{{ cookiecutter.project_name }} {{ cookiecutter.project_name }}
{% raw %} {% raw %} {% endblock %}
{% endblock %}
</title> </title>
<meta name="description" content="{% block meta_description %}{% endblock %}"> <meta
<meta name="author" content="{% block meta_author %}{% endblock %}"> name="description"
content="{% block meta_description %}{% endblock %}"
/>
<meta name="author" content="{% block meta_author %}{% endblock %}" />
<!-- Mobile viewport optimized: h5bp.com/viewport --> <!-- Mobile viewport optimized: h5bp.com/viewport -->
<meta name="viewport" content="width=device-width"> <meta name="viewport" content="width=device-width" />
{{ stylesheet_tag('main_css') | safe }} <link
rel="stylesheet"
type="text/css"
href="{{ static_url_for('static', filename='build/main_css.css') }}"
/>
{% block css %}{% endblock %} {% block css %}{% endblock %}
</head>
<body class="{% block body_class %}{% endblock %}">
{% block body %} {% with form=form %} {% include "nav.html" %} {% endwith %}
</head> <header>{% block header %}{% endblock %}</header>
<body class="{% block body_class %}{% endblock %}">
{% block body %}
{% with form=form %}
{% include "nav.html" %}
{% endwith %}
<header>{% block header %}{% endblock %}</header>
<main role="main"> <main role="main">
{% with messages = get_flashed_messages(with_categories=true) %} {% with messages = get_flashed_messages(with_categories=true) %} {% if
{% if messages %} messages %}
<div class="row"> <div class="row">
<div class="col-md-12"> <div class="col-md-12">
{% for category, message in messages %} {% for category, message in messages %}
<div class="alert alert-{{ category }}"> <div class="alert alert-{{ category }}">
<a class="close" title="Close" href="#" data-dismiss="alert">&times;</a> <a class="close" title="Close" href="#" data-dismiss="alert"
{{message}} >&times;</a
</div><!-- end .alert --> >
{{ message }}
</div>
<!-- end .alert -->
{% endfor %} {% endfor %}
</div><!-- end col-md --> </div>
</div><!-- end row --> <!-- end col-md -->
{% endif %} </div>
{% endwith %} <!-- end row -->
{% endif %} {% endwith %} {% block content %}{% endblock %}
{% block content %}{% endblock %} </main>
</main>
{% include "footer.html" %}
{% include "footer.html" %} <!-- JavaScript at the bottom for fast page loading -->
<script src="{{ static_url_for('static', filename='build/main_js.js') }}"></script>
<!-- JavaScript at the bottom for fast page loading --> {% block js %}{% endblock %}
{{ javascript_tag('main_js') | safe }} <!-- end scripts -->
{% block js %}{% endblock %} {% endblock %}
<!-- end scripts --> </body>
{% endblock %}
</body>
</html> </html>
{% endraw %} {% endraw %}

Loading…
Cancel
Save