Skip to content

Commit

Permalink
Merge pull request #16 from nejch/feat/minify-css
Browse files Browse the repository at this point in the history
Add support for minifying CSS files
  • Loading branch information
Lars Wilhelmer authored Oct 18, 2021
2 parents 67ec6b8 + b85e01d commit 276bf84
Show file tree
Hide file tree
Showing 11 changed files with 173 additions and 31 deletions.
25 changes: 25 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
name: Test

on:
push:
branches:
- master
pull_request:
branches:
- master

jobs:
test:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: "3.10"
- name: Install dependencies
run: |
pip install -r tests/requirements.txt
pip install -e .
- name: Run tests
run: pytest -v
13 changes: 11 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
# mkdocs-minify-plugin

An MkDocs plugin to minify HTML and/or JS files prior to being written to disk.
An MkDocs plugin to minify HTML, JS or CSS files prior to being written to disk.

HTML minification is done using [htmlmin](https://github.com/mankyd/htmlmin).

JS minification is done using [jsmin](https://github.com/tikitu/jsmin/).

CSS minification is done using [csscompressor](https://github.com/sprymix/csscompressor).

## Setup

Install the plugin using pip:
Expand All @@ -19,11 +21,15 @@ plugins:
- minify:
minify_html: true
minify_js: true
minify_css: true
htmlmin_opts:
remove_comments: true
js_files:
- my/javascript/dir/file1.js
- my/javascript/dir/file2.js
css_files:
- my/css/dir/file1.css
- my/css/dir/file2.css
```
> **Note:** If you have no `plugins` entry in your config file yet, you'll likely also want to add the `search` plugin. MkDocs enables it by default if there is no `plugins` entry set, but now you have to enable it explicitly.
Expand All @@ -33,9 +39,12 @@ plugins:
- `minify_html`: Sets whether HTML files should be minified. Defaults to `false`.
- `htmlmin_opts`: Sets runtime htmlmin API options using the [config parameters of htmlmin](https://htmlmin.readthedocs.io/en/latest/reference.html#main-functions)
- `minify_js`: Sets whether JS files should be minified. Defaults to `false`. If set to `true`, you must specificy the JS to be minified files using `js_files` (see below).
- `minify_css`: Sets whether CSS files should be minified. Defaults to `false`. If set to `true`, you must specificy the CSS to be minified files using `css_files` (see below).
- `js_files`: List of JS files to be minified. The plugin will generate minified versions of these files and save them as `.min.js` in the output directory.
- `css_files`: List of CSS files to be minified. The plugin will generate minified versions of these files and save them as `.min.css` in the output directory.

> **Note:** When using `minify_js`, you don't have to modify the `extra_javascript` entries in your `mkdocs.yml` file. The plugins automatically takes care of that.
> **Note:** When using `minify_jss` or `minify_css`, you don't have to modify the `extra_javascript` or `extra_css` entries
in your `mkdocs.yml` file. The plugins automatically takes care of that.

More information about plugins in the [MkDocs documentation][mkdocs-plugins].

Expand Down
83 changes: 58 additions & 25 deletions mkdocs_minify_plugin/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,67 @@
from mkdocs.plugins import BasePlugin
import mkdocs.structure.files

from jsmin import jsmin
import csscompressor
import jsmin
from htmlmin import minify


EXTRAS = {
"js": "extra_javascript",
"css": "extra_css",
}
MINIFIERS = {
"js": jsmin.jsmin,
"css": csscompressor.compress
}


def _minified_asset(file_name, file_type):
return file_name.replace('.' + file_type, '.min.' + file_type)


class MinifyPlugin(BasePlugin):

config_scheme = (
('minify_html', mkdocs.config.config_options.Type(bool, default=False)),
('htmlmin_opts', mkdocs.config.config_options.Type((str, dict), default=None)),
('minify_js', mkdocs.config.config_options.Type(bool, default=False)),
('js_files', mkdocs.config.config_options.Type((str, list), default=None))
('minify_css', mkdocs.config.config_options.Type(bool, default=False)),
('js_files', mkdocs.config.config_options.Type((str, list), default=None)),
('css_files', mkdocs.config.config_options.Type((str, list), default=None)),
('htmlmin_opts', mkdocs.config.config_options.Type((str, dict), default=None)),
)

def _minify(self, file_type, config):
minify_func = MINIFIERS[file_type]
files = self.config[file_type + '_files'] or []

if not isinstance(files, list):
files = [files]
for file in files:
# Read file and minify
fn = config['site_dir'] + '/' + file
if os.sep != '/':
fn = fn.replace(os.sep, '/')
with open(fn, mode="r+", encoding="utf-8") as f:
minified = minify_func(f.read())
f.seek(0)
f.write(minified)
f.truncate()
# Rename to .min.{file_type}
os.rename(fn, _minified_asset(fn, file_type))

def _minify_extra_config(self, file_type, config):
"""Change extra_ entries so they point to the minified files."""
files = self.config[file_type + '_files'] or []
extra = EXTRAS[file_type]

if not isinstance(files, list):
files = [files]
for file in files:
if file in config[extra]:
config[extra][config[extra].index(file)] = _minified_asset(file, file_type)
return config

def on_post_page(self, output_content, page, config):
if self.config['minify_html']:
opts = self.config['htmlmin_opts'] or {}
Expand All @@ -40,30 +89,14 @@ def on_post_template(self, output_content, template_name, config):

def on_pre_build(self, config):
if self.config['minify_js']:
jsfiles = self.config['js_files'] or []
if not isinstance(jsfiles, list):
jsfiles = [jsfiles]
for jsfile in jsfiles:
# Change extra_javascript entries so they point to the minified files
if jsfile in config['extra_javascript']:
config['extra_javascript'][config['extra_javascript'].index(jsfile)] = jsfile.replace('.js', '.min.js')
config = self._minify_extra_config('js', config)
if self.config['minify_css']:
config = self._minify_extra_config('css', config)
return config

def on_post_build(self, config):
if self.config['minify_js']:
jsfiles = self.config['js_files'] or []
if not isinstance(jsfiles, list):
jsfiles = [jsfiles]
for jsfile in jsfiles:
# Read JS file and minify
fn = config['site_dir'] + '/' + jsfile
if os.sep != '/':
fn = fn.replace(os.sep, '/')
with open(fn, mode="r+", encoding="utf-8") as f:
minified = jsmin(f.read())
f.seek(0)
f.write(minified)
f.truncate()
# Rename to .min.js
os.rename(fn, fn.replace('.js','.min.js'))
self._minify('js', config)
if self.config['minify_css']:
self._minify('css', config)
return config
3 changes: 2 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mkdocs>=1.0.4
htmlmin>=0.1.4
jsmin>=3.0.0
jsmin>=3.0.0
csscompressor>=0.9.5
9 changes: 6 additions & 3 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

setup(
name='mkdocs-minify-plugin',
version='0.4.1',
description='An MkDocs plugin to minify HTML and/or JS files prior to being written to disk',
version='0.5.0',
description='An MkDocs plugin to minify HTML, JS or CSS files prior to being written to disk',
long_description='',
keywords='mkdocs minify publishing documentation html css',
url='https://github.com/byrnereese/mkdocs-minify-plugin',
Expand All @@ -12,7 +12,10 @@
license='MIT',
python_requires='>=3.0',
install_requires=[
'mkdocs>=1.0.4','htmlmin>=0.1.4', 'jsmin>=3.0.0'
'mkdocs>=1.0.4',
'htmlmin>=0.1.4',
'jsmin>=3.0.0',
'csscompressor>=0.9.5',
],
classifiers=[
'Development Status :: 4 - Beta',
Expand Down
4 changes: 4 additions & 0 deletions tests/fixtures/docs/extra_assets/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
/* extra css */
.ui-hidden {
display: none;
}
2 changes: 2 additions & 0 deletions tests/fixtures/docs/extra_assets/js/script.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
// extra js
console.log('Hello World');
17 changes: 17 additions & 0 deletions tests/fixtures/docs/index.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# Welcome to MkDocs

For full documentation visit [mkdocs.org](https://www.mkdocs.org).

## Commands

* `mkdocs new [dir-name]` - Create a new project.
* `mkdocs serve` - Start the live-reloading docs server.
* `mkdocs build` - Build the documentation site.
* `mkdocs -h` - Print help message and exit.

## Project layout

mkdocs.yml # The configuration file.
docs/
index.md # The documentation homepage.
... # Other markdown pages, images and other files.
14 changes: 14 additions & 0 deletions tests/fixtures/mkdocs.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
site_name: My Docs

plugins:
- search
- minify:
minify_html: true
minify_js: true
minify_css: true
htmlmin_opts:
remove_comments: true
js_files:
- extra_assets/js/script.js
css_files:
- extra_assets/css/style.css
1 change: 1 addition & 0 deletions tests/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pytest>=6.2.5,<7.0.0
33 changes: 33 additions & 0 deletions tests/test_basic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
from distutils.dir_util import copy_tree
from pathlib import Path
from subprocess import check_call

import pytest


@pytest.fixture
def extra_dir(tmp_path):
return tmp_path / "site" / "extra_assets"


@pytest.fixture
def mkdocs_build(tmp_path):
fixture_dir = str(Path(__file__).parent / "fixtures")
temp_dir = str(tmp_path)

copy_tree(fixture_dir, temp_dir)
return check_call(["mkdocs", "build", "-f", f"{temp_dir}/mkdocs.yml"])


def test_css_is_minified(mkdocs_build, extra_dir):
with open(extra_dir / "css" / "style.min.css", "r") as f:
minified = f.read()

assert minified == r".ui-hidden{display:none}"


def test_js_is_minifed(mkdocs_build, extra_dir):
with open(extra_dir / "js" / "script.min.js", "r") as f:
minifed = f.read()

assert minifed == r"console.log('Hello World');"

0 comments on commit 276bf84

Please sign in to comment.