forked from zulip/zulip
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathminify-js
executable file
·149 lines (120 loc) · 5.82 KB
/
minify-js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
#!/usr/bin/env python
# Minifies JavaScripts, creating source maps
from __future__ import absolute_import
from __future__ import print_function
import os
import subprocess
import argparse
import sys
import six
parser = argparse.ArgumentParser()
parser.add_argument('--prev-deploy', metavar='DIR',
help='a previous deploy from which to reuse files if possible')
args = parser.parse_args()
prev_deploy = args.prev_deploy
# We have to pull out JS_SPECS, defined in our settings file, so we know what
# JavaScript source files to minify (and what output files to create).
sys.path.insert(0, os.path.join(os.path.dirname(__file__), '..'))
import scripts.lib.setup_path_on_import
from typing import Optional, Set
os.environ['DJANGO_SETTINGS_MODULE'] = 'zproject.settings'
from django.conf import settings
os.chdir(settings.DEPLOY_ROOT)
STATIC_PATH = 'static/'
# Compile Handlebars templates
subprocess.check_call(['tools/compile-handlebars-templates'])
# Create webpack bundle
subprocess.check_call(['tools/webpack'])
def get_changed_source_files(other_checkout):
# type: (Optional[str]) -> Optional[Set[str]]
""" Get list of changed static files since other_checkout.
If git fails to return a reasonable looking list, this returns None,
in which case it should be assumed no files can be reused from
other_checkout. """
try:
git_dir = os.path.join(other_checkout, '.git')
old_commit_sha1 = subprocess.check_output(['git', 'rev-parse', 'HEAD'],
env={'GIT_DIR': git_dir}, universal_newlines=True)
old_commit_sha1 = old_commit_sha1.rstrip()
git_diff = subprocess.check_output(['git', 'diff', '--name-only',
old_commit_sha1], universal_newlines=True)
except subprocess.CalledProcessError:
# If git returned an error, assume we can't reuse any files, and
# regenerate everything.
print("Warning: git returned an error when comparing to the previous")
print("deploy in %s. Will re-minify JavaScript instead of reusing"
% (other_checkout,))
return None
changed = set() # type: Set[str]
for filename in git_diff.split('\n'):
if filename in ["package.json", "zproject/settings.py", "tools/minify-js",
"tools/tools/webpack.production.config.js"]:
print("Changed a core JS pipeline file; not reusing cached minification results")
return None
if not filename.startswith(STATIC_PATH):
continue # Ignore non-static files.
if filename.endswith('.handlebars'):
continue
changed.add(filename)
return changed
changed_files = set() # type: Set[str]
if prev_deploy:
changed_files = get_changed_source_files(prev_deploy)
if changed_files is None:
prev_deploy = None
# Always use the newly compiled handlebars templates and webpack bundle.
if prev_deploy:
changed_files.add(os.path.join(STATIC_PATH, 'templates/compiled.js'))
changed_files.add(os.path.join(STATIC_PATH, 'js/bundle.js'))
JS_SPECS = settings.JS_SPECS
CLOSURE_BINARY = '/usr/bin/closure-compiler'
if not os.path.exists(CLOSURE_BINARY):
CLOSURE_BINARY = 'tools/closure-compiler/run'
if not os.path.exists(CLOSURE_BINARY):
print("closure-compiler not installed; the Vagrant tools/provision installs it via apt "
"or you can manually unpack http://dl.google.com/closure-compiler/compiler-latest.zip to "
"tools/closure-compiler")
sys.exit(1)
# Where to put minified JS and source maps
MIN_DIR = os.path.join(STATIC_PATH, 'min/')
MAP_DIR = os.path.join(STATIC_PATH, 'source-map/')
subprocess.check_call(['mkdir', '-p', MIN_DIR, MAP_DIR])
for js_group, filespec in six.iteritems(JS_SPECS):
# JS_SPECS look like 'js/foobar.js'.
# changed_files look like 'static/js/foobar.js'.
# So we prepend 'static/' to the JS_SPECS so these match up.
in_files = [os.path.join(STATIC_PATH, filename)
for filename in filespec['source_filenames']]
min_files = [os.path.join(STATIC_PATH, filename)
for filename in filespec.get('minifed_source_filenames', [])]
out_file = os.path.join(MIN_DIR, os.path.basename(filespec['output_filename']))
map_file = os.path.join(MAP_DIR, os.path.basename(filespec['output_filename']) +
'.map')
if ('force_minify' not in filespec) and \
(prev_deploy and len(set(in_files) & changed_files) == 0):
# Try to reuse the output file from previous deploy
try:
for dest in [out_file, map_file]:
src = os.path.join(prev_deploy, dest)
os.path.getsize(src) # Just to throw error if it doesn't exist.
if os.path.abspath(src) != os.path.abspath(dest):
subprocess.check_call(['cp', src, dest])
continue # Copy succeeded, so go on to next file.
except (subprocess.CalledProcessError, OSError):
pass # Copy failed, so fall through to minification instead.
# No previous deploy, or a source file has changed, or copying was
# supposed to work but failed. Thus, minify the JS anew.
# (N.B. we include STATIC_HEADER_FILE before the JavaScripts.
# This way it doesn't throw off the source map.)
cmd = '%s --language_in ECMASCRIPT5 --create_source_map %s %s %s' % (
CLOSURE_BINARY, map_file,
settings.STATIC_HEADER_FILE, ' '.join(in_files))
js = subprocess.check_output(cmd, shell=True)
# Write out the JS
with open(out_file, 'wb') as fp:
# Minified source files (most likely libraries) should be loaded
# first to prevent any dependency errors.
for file in min_files:
with open(file, 'rb') as f:
fp.write(f.read())
fp.write(js)