3
_____ _ _____ __ __ _____ _______
4
/ ____| | |_ _| \/ |_ _|__ __|
5
| (___ | | | | | \ / | | | | |
6
\___ \| | | | | |\/| | | | | |
7
____) | |____ _| |_| | | |_| |_ | |
8
|_____/|______|_____|_| |_|_____| |_|
12
==================================
14
`SlimIt` is a JavaScript minifier written in Python.
15
It compiles JavaScript into more compact code so that it downloads
18
`SlimIt` also provides a library that includes a JavaScript parser,
19
lexer, pretty printer and a tree visitor.
21
`http://slimit.readthedocs.org/ <http://slimit.readthedocs.org/>`_
28
$ [sudo] pip install slimit
30
Or the bleeding edge version from the git master branch:
34
$ [sudo] pip install git+https://github.com/rspivak/slimit.git#egg=slimit
37
Let's minify some code
38
----------------------
40
From the command line:
45
Usage: slimit [options] [input file]
47
If no input file is provided STDIN is used by default.
48
Minified JavaScript code is printed to STDOUT.
51
-h, --help show this help message and exit
52
-m, --mangle mangle names
54
mangle top level scope (defaults to False)
57
var foo = function( obj ) {
58
for ( var name in obj ) {
64
$ slimit --mangle < test.js
65
var foo=function(a){for(var b in a)return false;return true;};
69
>>> from slimit import minify
71
... var foo = function( obj ) {
72
... for ( var name in obj ) {
78
>>> print minify(text, mangle=True, mangle_toplevel=True)
79
var a=function(a){for(var b in a)return false;return true;};
82
Iterate over, modify a JavaScript AST and pretty print it
83
---------------------------------------------------------
85
>>> from slimit.parser import Parser
86
>>> from slimit.visitors import nodevisitor
87
>>> from slimit import ast
90
>>> tree = parser.parse('for(var i=0; i<10; i++) {var x=5+i;}')
91
>>> for node in nodevisitor.visit(tree):
92
... if isinstance(node, ast.Identifier) and node.value == 'i':
93
... node.value = 'hello'
95
>>> print tree.to_ecma() # print awesome javascript :)
96
for (var hello = 0; hello < 10; hello++) {
101
Writing custom node visitor
102
---------------------------
104
>>> from slimit.parser import Parser
105
>>> from slimit.visitors.nodevisitor import ASTVisitor
109
... "key1": "value1",
114
>>> class MyVisitor(ASTVisitor):
115
... def visit_Object(self, node):
116
... """Visit object literal."""
117
... for prop in node:
118
... left, right = prop.left, prop.right
119
... print 'Property key=%s, value=%s' % (left.value, right.value)
120
... # visit all children in turn
124
>>> parser = Parser()
125
>>> tree = parser.parse(text)
126
>>> visitor = MyVisitor()
127
>>> visitor.visit(tree)
128
Property key="key1", value="value1"
129
Property key="key2", value="value2"
131
Using lexer in your project
132
---------------------------
134
>>> from slimit.lexer import Lexer
136
>>> lexer.input('a = 1;')
137
>>> for token in lexer:
142
LexToken(NUMBER,'1',1,4)
143
LexToken(SEMI,';',1,5)
145
You can get one token at a time using ``token`` method:
147
>>> lexer.input('a = 1;')
149
... token = lexer.token()
156
LexToken(NUMBER,'1',1,4)
157
LexToken(SEMI,';',1,5)
159
`LexToken` instance has different attributes:
161
>>> lexer.input('a = 1;')
162
>>> token = lexer.token()
163
>>> token.type, token.value, token.lineno, token.lexpos
169
**SAM** - JQuery size after minification in bytes (the smaller number the better)
171
+-------------------------------+------------+------------+------------+
172
| Original jQuery 1.6.1 (bytes) | SlimIt SAM | rJSmin SAM | jsmin SAM |
173
+===============================+============+============+============+
174
| 234,995 | 94,290 | 134,215 | 134,819 |
175
+-------------------------------+------------+------------+------------+
179
- when doing name mangling handle cases with 'eval' and 'with'
180
- foo["bar"] ==> foo.bar
181
- consecutive declarations: var a = 10; var b = 20; ==> var a=10,b=20;
182
- reduce simple constant expressions if the result takes less space:
184
- IF statement optimizations
186
1. if (foo) bar(); else baz(); ==> foo?bar():baz();
187
2. if (!foo) bar(); else baz(); ==> foo?baz():bar();
188
3. if (foo) bar(); ==> foo&&bar();
189
4. if (!foo) bar(); ==> foo||bar();
190
5. if (foo) return bar(); else return baz(); ==> return foo?bar():baz();
191
6. if (foo) return bar(); else something(); ==> {if(foo)return bar();something()}
193
- remove unreachable code that follows a return, throw, break or
194
continue statement, except function/variable declarations
195
- parsing speed improvements
199
- The lexer and parser are built with `PLY <http://www.dabeaz.com/ply/>`_
200
- Several test cases and regexes from `jslex <https://bitbucket.org/ned/jslex>`_
201
- Some visitor ideas - `pycparser <http://code.google.com/p/pycparser/>`_
202
- Many grammar rules are taken from `rkelly <https://github.com/tenderlove/rkelly>`_
203
- Name mangling and different optimization ideas - `UglifyJS <https://github.com/mishoo/UglifyJS>`_
204
- ASI implementation was inspired by `pyjsparser <http://bitbucket.org/mvantellingen/pyjsparser>`_
208
The MIT License (MIT)
b'\\ No newline at end of file'