Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 3 additions & 4 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,9 @@ python:
- 2.7
- 3.4
before_install:
- nvm install 4.0
- npm install -g node-sass postcss-cli autoprefixer
- npm install -g browserify babelify babel-preset-es2015
- nvm install 6.0
- npm install
install:
- pip install -e .[test]
script:
- py.test
- py.test tests/unit_tests tests/integration_tests
67 changes: 54 additions & 13 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ $title-size: 30px;

You need `node-sass`, `postcss-cli` and `autoprefixer` to be installed. Quick install:

```sh
npm install node-sass postcss-cli autoprefixer
```

Or you can install them globally (you need to set `COMPRESS_LOCAL_NPM_INSTALL = False`):

```sh
npm install -g node-sass postcss-cli autoprefixer
```
Expand Down Expand Up @@ -136,55 +142,89 @@ export default class {

You need `browserify`, `babelify` and `babel-preset-es2015` to be installed. Quick install:

```sh
npm install browserify babelify babel-preset-es2015
```

Or you can install them globally (you need to set `COMPRESS_LOCAL_NPM_INSTALL = False`):

```sh
npm install -g browserify babelify babel-preset-es2015
```

## Django settings

### `COMPRESS_LOCAL_NPM_INSTALL`

Whether you install required NPM packages _locally_.

Default: `True`.

### `COMPRESS_NODE_MODULES`

Path to `node_modules` where `browserify`, `babelify`, `autoprefixer`, etc, are installed.
Path to `node_modules` where `babelify`, `autoprefixer`, etc, libs are installed.

Default: `./node_modules` if `COMPRESS_LOCAL_NPM_INSTALL` else `/usr/lib/node_modules`.

### `COMPRESS_NODE_SASS_BIN`

`node-sass` executable. It may be just the executable name (if it's on `PATH`) or the executable path.

Default: `./node_modules/.bin/node-sass` if `COMPRESS_LOCAL_NPM_INSTALL` else `node-sass`.

Default: `/usr/lib/node_modules`
### `COMPRESS_POSTCSS_BIN`

`postcss` executable. It may be just the executable name (if it's on `PATH`) or the executable path.

Default: `./node_modules/.bin/postcss` if `COMPRESS_LOCAL_NPM_INSTALL` else `postcss`.

### `COMPRESS_AUTOPREFIXER_BROWSERS`

Browser versions config for Autoprefixer.

Default: `ie >= 9, > 5%`.

### `COMPRESS_SCSS_COMPILER_CMD`

Command that will be executed to transform SCSS into CSS code.

Default:

```sh
node-sass --output-style expanded {paths} "{infile}" "{outfile}" &&
postcss --use "{node_modules}/autoprefixer" --autoprefixer.browsers "{autoprefixer_browsers}" -r "{outfile}"
```py
'{node_sass_bin} --output-style expanded {paths} "{infile}" "{outfile}" && '
'{postcss_bin} --use "{node_modules}/autoprefixer" --autoprefixer.browsers "{autoprefixer_browsers}" -r "{outfile}"'
```

Placeholders:
Placeholders (i.e. they **can be re-used** in custom `COMPRESS_SCSS_COMPILER_CMD` string):
- `{node_sass_bin}` - value from `COMPRESS_NODE_SASS_BIN`
- `{postcss_bin}` - value from `COMPRESS_POSTCSS_BIN`
- `{infile}` - input file path
- `{outfile}` - output file path
- `{paths}` - specially for `node-sass`, include all Django app static folders:
`--include-path=/path/to/app-1/static/ --include-path=/path/to/app-2/static/ ...`
- `{node_modules}` - see `COMPRESS_NODE_MODULES` setting
- `{autoprefixer_browsers}` - see `COMPRESS_AUTOPREFIXER_BROWSERS` setting
- `{autoprefixer_browsers}` - value from `COMPRESS_AUTOPREFIXER_BROWSERS`

### `COMPRESS_AUTOPREFIXER_BROWSERS`
### `COMPRESS_BROWSERIFY_BIN`

Browser versions config for Autoprefixer.
`browserify` executable. It may be just the executable name (if it's on `PATH`) or the executable path.

Default: `ie >= 9, > 5%`
Default: `./node_modules/.bin/browserify` if `COMPRESS_LOCAL_NPM_INSTALL` else `browserify`.

### `COMPRESS_ES6_COMPILER_CMD`

Command that will be executed to transform ES6 into ES5 code.

Default:

```sh
export NODE_PATH="{paths}" && browserify "{infile}" -o "{outfile}" --no-bundle-external --node
-t [ "{node_modules}/babelify" --presets="{node_modules}/babel-preset-es2015" ]
```py
'export NODE_PATH="{paths}" && '
'{browserify_bin} "{infile}" -o "{outfile}" --no-bundle-external --node '
'-t [ "{node_modules}/babelify" --presets="{node_modules}/babel-preset-es2015" ]'
```

Placeholders:
- `{browserify_bin}` - value from `COMPRESS_BROWSERIFY_BIN`
- `{infile}` - input file path
- `{outfile}` - output file path
- `{paths}` - specially for `browserify`, include all Django app static folders:
Expand All @@ -197,5 +237,6 @@ Placeholders:
git clone https://github.com/kottenator/django-compressor-toolkit.git
cd django-compressor-toolkit
pip install -e '.[test]'
npm install
py.test
```
2 changes: 1 addition & 1 deletion compressor_toolkit/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# PEP 440 - version number format
VERSION = (0, 5, 1, 'dev0')
VERSION = (0, 6, 0, 'dev0')

# PEP 396 - module version variable
__version__ = '.'.join(map(str, VERSION))
Expand Down
49 changes: 38 additions & 11 deletions compressor_toolkit/apps.py
Original file line number Diff line number Diff line change
@@ -1,28 +1,55 @@
import os

from django.apps.config import AppConfig
from django.conf import settings


class CompressorToolkitConfig(AppConfig):
name = 'compressor_toolkit'

LOCAL_NPM_INSTALL = getattr(settings, 'COMPRESS_LOCAL_NPM_INSTALL', True)

# Path to 'node_modules' where browserify, babelify, autoprefixer, etc, are installed
NODE_MODULES = getattr(settings, 'COMPRESS_NODE_MODULES', None) or '/usr/lib/node_modules'
NODE_MODULES = getattr(
settings,
'COMPRESS_NODE_MODULES',
os.path.abspath('node_modules') if LOCAL_NPM_INSTALL else '/usr/lib/node_modules'
)

# Custom SCSS transpiler command
SCSS_COMPILER_CMD = getattr(settings, 'COMPRESS_SCSS_COMPILER_CMD', None) or (
'node-sass --output-style expanded {paths} "{infile}" "{outfile}" && '
'postcss --use "{node_modules}/autoprefixer" '
'--autoprefixer.browsers "{autoprefixer_browsers}" -r "{outfile}"'
# node-sass executable
NODE_SASS_BIN = getattr(
settings,
'COMPRESS_NODE_SASS_BIN',
'node_modules/.bin/node-sass' if LOCAL_NPM_INSTALL else 'node-sass'
)

# postcss executable
POSTCSS_BIN = getattr(
settings,
'COMPRESS_POSTCSS_BIN',
'node_modules/.bin/node-sass' if LOCAL_NPM_INSTALL else 'postcss'
)

# Browser versions config for Autoprefixer
AUTOPREFIXER_BROWSERS = getattr(settings, 'COMPRESS_AUTOPREFIXER_BROWSERS', None) or (
'ie >= 9, > 5%'
AUTOPREFIXER_BROWSERS = getattr(settings, 'COMPRESS_AUTOPREFIXER_BROWSERS', 'ie >= 9, > 5%')

# Custom SCSS transpiler command
SCSS_COMPILER_CMD = getattr(settings, 'COMPRESS_SCSS_COMPILER_CMD', (
'{node_sass_bin} --output-style expanded {paths} "{infile}" > "{outfile}" && '
'{postcss_bin} --use "{node_modules}/autoprefixer" '
'--autoprefixer.browsers "{autoprefixer_browsers}" -r "{outfile}"'
))

# browserify executable
BROWSERIFY_BIN = getattr(
settings,
'COMPRESS_BROWSERIFY_BIN',
'node_modules/.bin/browserify' if LOCAL_NPM_INSTALL else 'browserify'
)

# Custom ES6 transpiler command
ES6_COMPILER_CMD = getattr(settings, 'COMPRESS_ES6_COMPILER_CMD', None) or (
ES6_COMPILER_CMD = getattr(settings, 'COMPRESS_ES6_COMPILER_CMD', (
'export NODE_PATH="{paths}" && '
'browserify "{infile}" -o "{outfile}" --no-bundle-external --node '
'{browserify_bin} "{infile}" -o "{outfile}" '
'-t [ "{node_modules}/babelify" --presets="{node_modules}/babel-preset-es2015" ]'
)
))
3 changes: 3 additions & 0 deletions compressor_toolkit/precompilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@ class SCSSCompiler(BaseCompiler):
"""
command = app_config.SCSS_COMPILER_CMD
options = (
('node_sass_bin', app_config.NODE_SASS_BIN),
('postcss_bin', app_config.POSTCSS_BIN),
('paths', ' '.join(['--include-path {}'.format(s) for s in get_all_static()])),
('node_modules', app_config.NODE_MODULES),
('autoprefixer_browsers', app_config.AUTOPREFIXER_BROWSERS),
Expand All @@ -103,6 +105,7 @@ class ES6Compiler(BaseCompiler):
"""
command = app_config.ES6_COMPILER_CMD
options = (
('browserify_bin', app_config.BROWSERIFY_BIN),
('paths', os.pathsep.join(get_all_static())),
('node_modules', app_config.NODE_MODULES)
)
Expand Down
11 changes: 11 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"private": true,
"devDependencies": {
"node-sass": "*",
"postcss-cli": "*",
"autoprefixer": "*",
"browserify": "*",
"babelify": "*",
"babel-preset-es2015": "*"
}
}
4 changes: 2 additions & 2 deletions setup.cfg
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
[pytest]
[tool:pytest]
python_paths = tests/test_project
testpaths = tests/unit_tests tests/integration_tests
addopts =
--ds test_project.settings
--cov compressor_toolkit
--cov-report term
--cov-report term-missing
--cov-report html
--cov-report xml
15 changes: 6 additions & 9 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,19 +18,16 @@
license='MIT',
packages=find_packages(exclude=['tests', 'tests.*']),
include_package_data=True,
setup_requires=[
'setuptools-git'
],
install_requires=[
'django-compressor~=1.5'
'django-compressor>=1.5'
],
extras_require={
'test': [
'django',
'pytest',
'pytest-django',
'pytest-cov',
'pytest-pythonpath'
'django~=1.8',
'pytest~=3.0',
'pytest-django~=3.0',
'pytest-cov~=2.4',
'pytest-pythonpath~=0.7'
]
},
classifiers=[
Expand Down
Empty file removed tests/__init__.py
Empty file.
Empty file.
36 changes: 30 additions & 6 deletions tests/integration_tests/test_views.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import re

from django.core.urlresolvers import reverse


Expand All @@ -10,8 +12,8 @@ def test_view_with_scss_file(client, precompiled):
"""
response = client.get(reverse('scss-file'))
assert response.status_code == 200
assert precompiled('app/layout.scss', 'css') == \
'.title {\n font: bold 30px Arial, sans-serif;\n}\n'
assert precompiled('app/layout.scss', 'css').strip() == \
'.title {\n font: bold 30px Arial, sans-serif;\n}'


def test_view_with_inline_scss(client):
Expand All @@ -22,9 +24,10 @@ def test_view_with_inline_scss(client):
"""
response = client.get(reverse('scss-inline'))
assert response.status_code == 200
assert b'<style type="text/css">' \
b'.title {\n font: bold 30px Arial, sans-serif;\n}\n' \
b'</style>' in response.content
assert re.search(
r'<style type="text/css">.title \{\n\s*font: bold 30px Arial, sans-serif;\n\}\s*</style>',
response.content.decode('utf8')
)


def test_view_with_es6_file(client, precompiled):
Expand Down Expand Up @@ -56,7 +59,28 @@ def test_view_with_es6_file(client, precompiled):
'new _framework2.default();\n'
'new _framework2.default(\'1.0.1\');\n'
'\n'
'},{"base/framework":undefined}]},{},[1]);\n'
'},{"base/framework":2}],2:[function(require,module,exports){\n'
'\'use strict\';\n'
'\n'
'Object.defineProperty(exports, "__esModule", {\n'
' value: true\n'
'});\n'
'\n'
'function _classCallCheck(instance, Constructor) {'
' if (!(instance instanceof Constructor)) {'
' throw new TypeError("Cannot call a class as a function"); } }\n'
'\n'
'var version = exports.version = \'1.0\';\n'
'\n'
'var _class = function _class(customVersion) {\n'
' _classCallCheck(this, _class);\n'
'\n'
' console.log(\'Framework v\' + (customVersion || version) + \' initialized\');\n'
'};\n'
'\n'
'exports.default = _class;\n'
'\n'
'},{}]},{},[1]);\n'
)


Expand Down
Empty file removed tests/test_project/__init__.py
Empty file.
26 changes: 21 additions & 5 deletions tests/test_project/test_project/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,25 @@
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'compressor.finders.CompressorFinder'
)
MIDDLEWARE_CLASSES = ()
TEMPLATE_CONTEXT_PROCESSORS = (
'django.template.context_processors.static',
)
# Django < 1.8
TEMPLATE_CONTEXT_PROCESSORS = [
'django.template.context_processors.static'
]
# Django >= 1.8
TEMPLATES = [{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.static'
]
}
}]
# Django < 1.10
MIDDLEWARE_CLASSES = []
# Django >= 1.10
MIDDLEWARE = []
# django-compressor settings
COMPRESS_ROOT = os.path.join(BASE_DIR, 'compressor')
COMPRESS_PRECOMPILERS = (
('text/x-scss', 'compressor_toolkit.precompilers.SCSSCompiler'),
Expand All @@ -30,4 +45,5 @@
COMPRESS_ENABLED = False

# django-compressor-toolkit settings; see compressor_toolkit/apps.py for details
COMPRESS_NODE_MODULES = os.getenv('COMPRESS_NODE_MODULES')
if 'COMPRESS_NODE_MODULES' in os.environ:
COMPRESS_NODE_MODULES = os.getenv('COMPRESS_NODE_MODULES')
Empty file removed tests/unit_tests/__init__.py
Empty file.
4 changes: 2 additions & 2 deletions tests/unit_tests/test_precompilers.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ def test_scss_compiler():
}
}
'''
output_css = '.a .b {\n padding-left: 5px;\n padding-right: 6px;\n}\n'
assert SCSSCompiler(input_scss, {}).input() == output_css
output_css = '.a .b {\n padding-left: 5px;\n padding-right: 6px;\n}'
assert SCSSCompiler(input_scss, {}).input().strip() == output_css


def test_es6_compiler():
Expand Down