mirror of
https://github.com/offen/website.git
synced 2024-11-22 09:00:28 +01:00
Merge pull request #96 from offen/asset-pipeline
Add asset pipeline to pelican setup
This commit is contained in:
commit
b493f1c8f8
@ -377,7 +377,7 @@ jobs:
|
||||
|
||||
deploy_homepage:
|
||||
docker:
|
||||
- image: circleci/python:3.6
|
||||
- image: circleci/python:3.6-node
|
||||
working_directory: ~/offen/homepage
|
||||
environment:
|
||||
- SOURCE_BRANCH: master
|
||||
@ -397,6 +397,11 @@ jobs:
|
||||
paths:
|
||||
- ~/offen/homepage/venv
|
||||
key: offen-homepage-{{ checksum "requirements.txt" }}
|
||||
- run:
|
||||
name: Install image optimization deps
|
||||
command: |
|
||||
npm install svgo -g
|
||||
sudo apt-get install libjpeg-progs optipng
|
||||
- run:
|
||||
name: Deploy
|
||||
command: |
|
||||
|
@ -12,6 +12,8 @@ services:
|
||||
command: make devserver
|
||||
ports:
|
||||
- 8000:8000
|
||||
environment:
|
||||
DEBUG: '1'
|
||||
|
||||
volumes:
|
||||
homepagedeps:
|
||||
|
@ -4,12 +4,10 @@ from __future__ import unicode_literals
|
||||
import logging
|
||||
|
||||
# If your site is available via HTTPS, make sure SITEURL begins with https://
|
||||
#SITEURL = 'https://www.offen.dev'
|
||||
RELATIVE_URLS = False
|
||||
|
||||
AUTHOR = 'offen'
|
||||
SITENAME = 'offen'
|
||||
SITEURL = 'https://www.offen.dev'
|
||||
PATH = 'content'
|
||||
TIMEZONE = 'Europe/Berlin'
|
||||
DEFAULT_LANG = 'en'
|
||||
@ -30,6 +28,9 @@ THEME = './theme'
|
||||
# Delete the output directory before generating new files.
|
||||
DELETE_OUTPUT_DIRECTORY = True
|
||||
|
||||
PLUGIN_PATHS = ['./plugins']
|
||||
PLUGINS = ['assets']
|
||||
|
||||
# dont create following standard pages
|
||||
AUTHORS_SAVE_AS = None
|
||||
ARCHIVES_SAVE_AS = None
|
||||
|
106
homepage/plugins/assets/Readme.rst
Normal file
106
homepage/plugins/assets/Readme.rst
Normal file
@ -0,0 +1,106 @@
|
||||
Asset management
|
||||
----------------
|
||||
|
||||
This plugin allows you to use the `Webassets`_ module to manage assets such as
|
||||
CSS and JS files. The module must first be installed::
|
||||
|
||||
pip install webassets
|
||||
|
||||
The Webassets module allows you to perform a number of useful asset management
|
||||
functions, including:
|
||||
|
||||
* CSS minifier (``cssmin``, ``yui_css``, ...)
|
||||
* CSS compiler (``less``, ``sass``, ...)
|
||||
* JS minifier (``uglifyjs``, ``yui_js``, ``closure``, ...)
|
||||
|
||||
Others filters include CSS URL rewriting, integration of images in CSS via data
|
||||
URIs, and more. Webassets can also append a version identifier to your asset
|
||||
URL to convince browsers to download new versions of your assets when you use
|
||||
far-future expires headers. Please refer to the `Webassets documentation`_ for
|
||||
more information.
|
||||
|
||||
When used with Pelican, Webassets is configured to process assets in the
|
||||
``OUTPUT_PATH/theme`` directory. You can use Webassets in your templates by
|
||||
including one or more template tags. The Jinja variable ``{{ ASSET_URL }}`` can
|
||||
be used in templates and is relative to the ``theme/`` url. The
|
||||
``{{ ASSET_URL }}`` variable should be used in conjunction with the
|
||||
``{{ SITEURL }}`` variable in order to generate URLs properly. For example:
|
||||
|
||||
.. code-block:: jinja
|
||||
|
||||
{% assets filters="cssmin", output="css/style.min.css", "css/inuit.css", "css/pygment-monokai.css", "css/main.css" %}
|
||||
<link rel="stylesheet" href="{{ SITEURL }}/{{ ASSET_URL }}">
|
||||
{% endassets %}
|
||||
|
||||
... will produce a minified css file with a version identifier that looks like:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<link href="http://{SITEURL}/theme/css/style.min.css?b3a7c807" rel="stylesheet">
|
||||
|
||||
These filters can be combined. Here is an example that uses the SASS compiler
|
||||
and minifies the output:
|
||||
|
||||
.. code-block:: jinja
|
||||
|
||||
{% assets filters="sass,cssmin", output="css/style.min.css", "css/style.scss" %}
|
||||
<link rel="stylesheet" href="{{ SITEURL }}/{{ ASSET_URL }}">
|
||||
{% endassets %}
|
||||
|
||||
Another example for Javascript:
|
||||
|
||||
.. code-block:: jinja
|
||||
|
||||
{% assets filters="uglifyjs", output="js/packed.js", "js/jquery.js", "js/base.js", "js/widgets.js" %}
|
||||
<script src="{{ SITEURL }}/{{ ASSET_URL }}"></script>
|
||||
{% endassets %}
|
||||
|
||||
The above will produce a minified JS file:
|
||||
|
||||
.. code-block:: html
|
||||
|
||||
<script src="http://{SITEURL}/theme/js/packed.js?00703b9d"></script>
|
||||
|
||||
Pelican's debug mode is propagated to Webassets to disable asset packaging
|
||||
and instead work with the uncompressed assets.
|
||||
|
||||
If you need to create named bundles (for example, if you need to compile SASS
|
||||
files before minifying with other CSS files), you can use the ``ASSET_BUNDLES``
|
||||
variable in your settings file. This is an ordered sequence of 3-tuples, where
|
||||
the 3-tuple is defined as ``(name, args, kwargs)``. This tuple is passed to the
|
||||
`environment's register() method`_. The following will compile two SCSS files
|
||||
into a named bundle, using the ``pyscss`` filter:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ASSET_BUNDLES = (
|
||||
('scss', ['colors.scss', 'main.scss'], {'filters': 'pyscss'}),
|
||||
)
|
||||
|
||||
Many of Webasset's available compilers have additional configuration options
|
||||
(i.e. 'Less', 'Sass', 'Stylus', 'Closure_js'). You can pass these options to
|
||||
Webassets using the ``ASSET_CONFIG`` in your settings file.
|
||||
|
||||
The following will handle Google Closure's compilation level and locate
|
||||
LessCSS's binary:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ASSET_CONFIG = (('closure_compressor_optimization', 'WHITESPACE_ONLY'),
|
||||
('less_bin', 'lessc.cmd'), )
|
||||
|
||||
If you wish to place your assets in locations other than the theme output
|
||||
directory, you can use ``ASSET_SOURCE_PATHS`` in your settings file to provide
|
||||
webassets with a list of additional directories to search, relative to the
|
||||
theme's top-level directory:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
ASSET_SOURCE_PATHS = [
|
||||
'vendor/css',
|
||||
'scss',
|
||||
]
|
||||
|
||||
.. _Webassets: https://github.com/miracle2k/webassets
|
||||
.. _Webassets documentation: http://webassets.readthedocs.org/en/latest/builtin_filters.html
|
||||
.. _environment's register() method: http://webassets.readthedocs.org/en/latest/environment.html#registering-bundles
|
1
homepage/plugins/assets/__init__.py
Normal file
1
homepage/plugins/assets/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .assets import *
|
75
homepage/plugins/assets/assets.py
Normal file
75
homepage/plugins/assets/assets.py
Normal file
@ -0,0 +1,75 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Asset management plugin for Pelican
|
||||
===================================
|
||||
|
||||
This plugin allows you to use the `webassets`_ module to manage assets such as
|
||||
CSS and JS files.
|
||||
|
||||
The ASSET_URL is set to a relative url to honor Pelican's RELATIVE_URLS
|
||||
setting. This requires the use of SITEURL in the templates::
|
||||
|
||||
<link rel="stylesheet" href="{{ SITEURL }}/{{ ASSET_URL }}">
|
||||
|
||||
.. _webassets: https://webassets.readthedocs.org/
|
||||
|
||||
"""
|
||||
from __future__ import unicode_literals
|
||||
|
||||
import os
|
||||
import logging
|
||||
|
||||
from pelican import signals
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
try:
|
||||
import webassets
|
||||
from webassets import Environment
|
||||
from webassets.ext.jinja2 import AssetsExtension
|
||||
except ImportError:
|
||||
webassets = None
|
||||
|
||||
def add_jinja2_ext(pelican):
|
||||
"""Add Webassets to Jinja2 extensions in Pelican settings."""
|
||||
|
||||
if 'JINJA_ENVIRONMENT' in pelican.settings: # pelican 3.7+
|
||||
pelican.settings['JINJA_ENVIRONMENT']['extensions'].append(AssetsExtension)
|
||||
else:
|
||||
pelican.settings['JINJA_EXTENSIONS'].append(AssetsExtension)
|
||||
|
||||
|
||||
def create_assets_env(generator):
|
||||
"""Define the assets environment and pass it to the generator."""
|
||||
|
||||
theme_static_dir = generator.settings['THEME_STATIC_DIR']
|
||||
assets_destination = os.path.join(generator.output_path, theme_static_dir)
|
||||
generator.env.assets_environment = Environment(
|
||||
assets_destination, theme_static_dir)
|
||||
|
||||
if 'ASSET_CONFIG' in generator.settings:
|
||||
for item in generator.settings['ASSET_CONFIG']:
|
||||
generator.env.assets_environment.config[item[0]] = item[1]
|
||||
|
||||
if 'ASSET_BUNDLES' in generator.settings:
|
||||
for name, args, kwargs in generator.settings['ASSET_BUNDLES']:
|
||||
generator.env.assets_environment.register(name, *args, **kwargs)
|
||||
|
||||
if 'ASSET_DEBUG' in generator.settings:
|
||||
generator.env.assets_environment.debug = generator.settings['ASSET_DEBUG']
|
||||
elif logging.getLevelName(logger.getEffectiveLevel()) == "DEBUG":
|
||||
generator.env.assets_environment.debug = True
|
||||
|
||||
for path in (generator.settings['THEME_STATIC_PATHS'] +
|
||||
generator.settings.get('ASSET_SOURCE_PATHS', [])):
|
||||
full_path = os.path.join(generator.theme, path)
|
||||
generator.env.assets_environment.append_path(full_path)
|
||||
|
||||
|
||||
def register():
|
||||
"""Plugin registration."""
|
||||
if webassets:
|
||||
signals.initialized.connect(add_jinja2_ext)
|
||||
signals.generator_init.connect(create_assets_env)
|
||||
else:
|
||||
logger.warning('`assets` failed to load dependency `webassets`.'
|
||||
'`assets` plugin not loaded.')
|
28
homepage/plugins/optimize_images/Readme.md
Normal file
28
homepage/plugins/optimize_images/Readme.md
Normal file
@ -0,0 +1,28 @@
|
||||
Optimize Images Plugin For Pelican
|
||||
==================================
|
||||
|
||||
This plugin applies lossless compression on JPEG, PNG and SVG images, with no
|
||||
effect on image quality via [jpegtran][], [OptiPNG][] and [svgo][] respectively.
|
||||
The plugin assumes that all of these tools are installed, with associated
|
||||
executables available on the system path.
|
||||
|
||||
[jpegtran]: http://jpegclub.org/jpegtran/
|
||||
[OptiPNG]: http://optipng.sourceforge.net/
|
||||
[SVGO]: https://github.com/svg/svgo
|
||||
|
||||
|
||||
Installation
|
||||
------------
|
||||
|
||||
To enable, ensure that `optimize_images.py` is put somewhere that is accessible.
|
||||
Then use as follows by adding the following to your settings.py:
|
||||
|
||||
PLUGIN_PATH = 'path/to/pelican-plugins'
|
||||
PLUGINS = ["optimize_images"]
|
||||
|
||||
`PLUGIN_PATH` can be a path relative to your settings file or an absolute path.
|
||||
|
||||
Usage
|
||||
-----
|
||||
The plugin will activate and optimize images upon `finalized` signal of
|
||||
Pelican.
|
1
homepage/plugins/optimize_images/__init__.py
Normal file
1
homepage/plugins/optimize_images/__init__.py
Normal file
@ -0,0 +1 @@
|
||||
from .optimize_images import *
|
61
homepage/plugins/optimize_images/optimize_images.py
Normal file
61
homepage/plugins/optimize_images/optimize_images.py
Normal file
@ -0,0 +1,61 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Optimized images (jpg and png)
|
||||
Assumes that jpegtran and optipng are isntalled on path.
|
||||
http://jpegclub.org/jpegtran/
|
||||
http://optipng.sourceforge.net/
|
||||
Copyright (c) 2012 Irfan Ahmad (http://i.com.pk)
|
||||
"""
|
||||
|
||||
import logging
|
||||
import os
|
||||
from subprocess import call
|
||||
|
||||
from pelican import signals
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
# Display command output on DEBUG and TRACE
|
||||
SHOW_OUTPUT = logger.getEffectiveLevel() <= logging.DEBUG
|
||||
|
||||
# A list of file types with their respective commands
|
||||
COMMANDS = {
|
||||
# '.ext': ('command {flags} {filename', 'silent_flag', 'verbose_flag')
|
||||
'.svg': ('svgo {flags} --input="{filename}" --output="{filename}"', '--quiet', ''),
|
||||
'.jpg': ('jpegtran {flags} -copy none -optimize -outfile "{filename}" "{filename}"', '', '-v'),
|
||||
'.png': ('optipng {flags} "{filename}"', '--quiet', ''),
|
||||
}
|
||||
|
||||
|
||||
def optimize_images(pelican):
|
||||
"""
|
||||
Optimized jpg and png images
|
||||
|
||||
:param pelican: The Pelican instance
|
||||
"""
|
||||
for dirpath, _, filenames in os.walk(pelican.settings['OUTPUT_PATH']):
|
||||
for name in filenames:
|
||||
if os.path.splitext(name)[1] in COMMANDS.keys():
|
||||
optimize(dirpath, name)
|
||||
|
||||
def optimize(dirpath, filename):
|
||||
"""
|
||||
Check if the name is a type of file that should be optimized.
|
||||
And optimizes it if required.
|
||||
|
||||
:param dirpath: Path of the file to be optimzed
|
||||
:param name: A file name to be optimized
|
||||
"""
|
||||
filepath = os.path.join(dirpath, filename)
|
||||
logger.info('optimizing %s', filepath)
|
||||
|
||||
ext = os.path.splitext(filename)[1]
|
||||
command, silent, verbose = COMMANDS[ext]
|
||||
flags = verbose if SHOW_OUTPUT else silent
|
||||
command = command.format(filename=filepath, flags=flags)
|
||||
call(command, shell=True)
|
||||
|
||||
|
||||
def register():
|
||||
signals.finalized.connect(optimize_images)
|
@ -19,9 +19,6 @@ CATEGORY_FEED_ATOM = 'feeds/{slug}.atom.xml'
|
||||
|
||||
DELETE_OUTPUT_DIRECTORY = True
|
||||
|
||||
# Following items are often useful when publishing
|
||||
|
||||
#DISQUS_SITENAME = ""
|
||||
#GOOGLE_ANALYTICS = ""
|
||||
PLUGINS += ['optimize_images']
|
||||
|
||||
OFFEN_ACCOUNT_ID = "5ec8345a-2a45-4eb9-92e5-8d9e5684db58"
|
||||
|
@ -1,2 +1,4 @@
|
||||
pelican==4.0.1
|
||||
markdown==3.1.1
|
||||
webassets==0.12.1
|
||||
cssmin==0.2.0
|
||||
|
@ -1,3 +1,7 @@
|
||||
;(function ($) {
|
||||
$(document).ready(function () {
|
||||
$(window).scroll(function () {
|
||||
$(".brand-index").css("opacity", 0 + $(window).scrollTop() / 100);
|
||||
});
|
||||
$('.brand-index').css('opacity', 0 + $(window).scrollTop() / 100)
|
||||
})
|
||||
})
|
||||
})(window.jQuery)
|
||||
|
@ -1,18 +1,16 @@
|
||||
(function($) {
|
||||
;(function ($) {
|
||||
$(function () {
|
||||
$('nav ul li a:not(:only-child)').click(function (e) {
|
||||
$(this).siblings('.nav-dropdown').toggle();
|
||||
$('.dropdown').not($(this).siblings()).hide();
|
||||
e.stopPropagation();
|
||||
});
|
||||
$(this).siblings('.nav-dropdown').toggle()
|
||||
$('.dropdown').not($(this).siblings()).hide()
|
||||
e.stopPropagation()
|
||||
})
|
||||
$('html').click(function () {
|
||||
$('.nav-dropdown').hide();
|
||||
});
|
||||
$('.nav-dropdown').hide()
|
||||
})
|
||||
$('#nav-toggle').click(function () {
|
||||
$('nav ul').slideToggle();
|
||||
});
|
||||
$('#nav-toggle').on('click', function() {
|
||||
this.classList.toggle('active');
|
||||
});
|
||||
});
|
||||
})(jQuery);
|
||||
$(this).closest('nav').find('ul').slideToggle()
|
||||
$(this).toggleClass('active')
|
||||
})
|
||||
})
|
||||
})(window.jQuery)
|
||||
|
@ -17,12 +17,9 @@
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<link rel="canonical" href="{{ SITEURL }}/{{ page.save_as }}">
|
||||
<link rel="shortcut icon" type="image/x-icon" href="/theme/images/favicon.ico">
|
||||
<link rel="stylesheet" type="text/css" href="/theme/css/normalize.css">
|
||||
<link rel="stylesheet" type="text/css" href="/theme/css/fonts.css">
|
||||
<!--
|
||||
<link rel="stylesheet" type="text/css" href="/theme/styles/index.css">
|
||||
-->
|
||||
<link rel="stylesheet" type="text/css" href="/theme/css/style.css">
|
||||
{% assets filters="cssmin", output="css/style.min.css", "css/normalize.css", "css/fonts.css", "css/style.css" %}
|
||||
<link rel="stylesheet" href="{{ SITEURL }}/{{ ASSET_URL }}">
|
||||
{% endassets %}
|
||||
{% if OFFEN_ACCOUNT_ID %}
|
||||
<script async src="https://script-alpha.offen.dev/script.js" data-account-id="{{ OFFEN_ACCOUNT_ID }}"></script>
|
||||
{% endif %}
|
||||
@ -40,7 +37,7 @@
|
||||
<a href="/"><img src="/theme/images/offen-brand-white.svg" alt="offen logo" width="42" height="46" class="logo"></a>
|
||||
</div>
|
||||
<nav>
|
||||
<div class="nav-mobile"><a id="nav-toggle" href="#!"><span></span></a></div>
|
||||
<div class="nav-mobile"><span id="nav-toggle"><span></span></span></div>
|
||||
<ul class="nav-list">
|
||||
<li>
|
||||
<a href="/">Summary</a>
|
||||
@ -240,9 +237,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="/theme/scripts/jquery-3.4.1.min.js"></script>
|
||||
<script src="/theme/scripts/menu.js"></script>
|
||||
<script src="/theme/scripts/fade.js"></script>
|
||||
|
||||
{% assets filters="rjsmin", output="scripts/packed.js", "scripts/jquery-3.4.1.min.js", "scripts/menu.js", "scripts/fade.js" %}
|
||||
<script src="{{ SITEURL }}/{{ ASSET_URL }}"></script>
|
||||
{% endassets %}
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user