]>
Commit | Line | Data |
---|---|---|
ae510306 SR |
1 | #!/usr/bin/env node |
2 | ||
3 | var path = require('path'); | |
4 | var program = require('commander'); | |
5 | var fs = require('fs'); | |
6 | var fse = require('fs-extra'); | |
ae510306 | 7 | |
6cae7b58 | 8 | const SUPPORTED_FORMATS = new Set(['amd', 'commonjs', 'systemjs', 'umd']); |
ae510306 SR |
9 | |
10 | program | |
6cae7b58 SR |
11 | .option('--as [format]', `output files using various import formats instead of ES6 import and export. Supports ${Array.from(SUPPORTED_FORMATS)}.`) |
12 | .option('-m, --with-source-maps [type]', 'output source maps when not generating a bundled app (type may be empty for external source maps, inline for inline source maps, or both) ') | |
13 | .option('--with-app', 'process app files as well as core files') | |
c4e5a50e | 14 | .option('--clean', 'clear the lib folder before building') |
ae510306 SR |
15 | .parse(process.argv); |
16 | ||
17 | // the various important paths | |
152c3995 SR |
18 | const paths = { |
19 | main: path.resolve(__dirname, '..'), | |
20 | core: path.resolve(__dirname, '..', 'core'), | |
21 | app: path.resolve(__dirname, '..', 'app'), | |
22 | vendor: path.resolve(__dirname, '..', 'vendor'), | |
23 | out_dir_base: path.resolve(__dirname, '..', 'build'), | |
24 | lib_dir_base: path.resolve(__dirname, '..', 'lib'), | |
25 | }; | |
ae510306 | 26 | |
adfc9d3f SR |
27 | const no_copy_files = new Set([ |
28 | // skip these -- they don't belong in the processed application | |
152c3995 SR |
29 | path.join(paths.vendor, 'sinon.js'), |
30 | path.join(paths.vendor, 'browser-es-module-loader'), | |
31 | path.join(paths.vendor, 'promise.js'), | |
adfc9d3f SR |
32 | ]); |
33 | ||
34 | const no_transform_files = new Set([ | |
35 | // don't transform this -- we want it imported as-is to properly catch loading errors | |
152c3995 | 36 | path.join(paths.app, 'error-handler.js'), |
adfc9d3f SR |
37 | ]); |
38 | ||
152c3995 SR |
39 | no_copy_files.forEach((file) => no_transform_files.add(file)); |
40 | ||
6cae7b58 SR |
41 | // walkDir *recursively* walks directories trees, |
42 | // calling the callback for all normal files found. | |
399fa2ee | 43 | var walkDir = function (base_path, cb, filter) { |
6cae7b58 SR |
44 | fs.readdir(base_path, (err, files) => { |
45 | if (err) throw err; | |
ae510306 | 46 | |
6cae7b58 SR |
47 | files.map((filename) => path.join(base_path, filename)).forEach((filepath) => { |
48 | fs.lstat(filepath, (err, stats) => { | |
49 | if (err) throw err; | |
ae510306 | 50 | |
399fa2ee SR |
51 | if (filter !== undefined && !filter(filepath, stats)) return; |
52 | ||
6cae7b58 SR |
53 | if (stats.isSymbolicLink()) return; |
54 | if (stats.isFile()) cb(filepath); | |
399fa2ee | 55 | if (stats.isDirectory()) walkDir(filepath, cb, filter); |
ae510306 SR |
56 | }); |
57 | }); | |
58 | }); | |
6cae7b58 | 59 | }; |
ae510306 | 60 | |
6cae7b58 | 61 | var transform_html = function (new_script) { |
ae510306 SR |
62 | // write out the modified vnc.html file that works with the bundle |
63 | var src_html_path = path.resolve(__dirname, '..', 'vnc.html'); | |
152c3995 | 64 | var out_html_path = path.resolve(paths.out_dir_base, 'vnc.html'); |
6cae7b58 | 65 | fs.readFile(src_html_path, (err, contents_raw) => { |
ae510306 SR |
66 | if (err) { throw err; } |
67 | ||
68 | var contents = contents_raw.toString(); | |
ae510306 SR |
69 | |
70 | var start_marker = '<!-- begin scripts -->\n'; | |
71 | var end_marker = '<!-- end scripts -->'; | |
72 | var start_ind = contents.indexOf(start_marker) + start_marker.length; | |
73 | var end_ind = contents.indexOf(end_marker, start_ind); | |
74 | ||
6cae7b58 | 75 | contents = contents.slice(0, start_ind) + `${new_script}\n` + contents.slice(end_ind); |
ae510306 | 76 | |
6cae7b58 | 77 | console.log(`Writing ${out_html_path}`); |
ae510306 SR |
78 | fs.writeFile(out_html_path, contents, function (err) { |
79 | if (err) { throw err; } | |
ae510306 SR |
80 | }); |
81 | }); | |
6cae7b58 | 82 | } |
ae510306 | 83 | |
6cae7b58 SR |
84 | var make_lib_files = function (import_format, source_maps, with_app_dir) { |
85 | if (!import_format) { | |
86 | throw new Error("you must specify an import format to generate compiled noVNC libraries"); | |
87 | } else if (!SUPPORTED_FORMATS.has(import_format)) { | |
88 | throw new Error(`unsupported output format "${import_format}" for import/export -- only ${Array.from(SUPPORTED_FORMATS)} are supported`); | |
89 | } | |
90 | ||
91 | // NB: we need to make a copy of babel_opts, since babel sets some defaults on it | |
92 | const babel_opts = () => ({ | |
93 | plugins: [`transform-es2015-modules-${import_format}`], | |
94 | ast: false, | |
95 | sourceMaps: source_maps, | |
96 | }); | |
97 | const babel = require('babel-core'); | |
98 | ||
99 | var in_path; | |
100 | if (with_app_dir) { | |
152c3995 SR |
101 | var out_path_base = paths.out_dir_base; |
102 | in_path = paths.main; | |
6cae7b58 | 103 | } else { |
152c3995 | 104 | var out_path_base = paths.lib_dir_base; |
6cae7b58 SR |
105 | } |
106 | ||
107 | fse.ensureDirSync(out_path_base); | |
108 | ||
109 | const helpers = require('./use_require_helpers'); | |
110 | const helper = helpers[import_format]; | |
a80955ee SR |
111 | |
112 | var handleDir = (js_only, vendor_rewrite, in_path_base, filename) => { | |
adfc9d3f SR |
113 | if (no_copy_files.has(filename)) return; |
114 | ||
6cae7b58 SR |
115 | const out_path = path.join(out_path_base, path.relative(in_path_base, filename)); |
116 | if(path.extname(filename) !== '.js') { | |
117 | if (!js_only) { | |
118 | console.log(`Writing ${out_path}`); | |
119 | fse.copy(filename, out_path, (err) => { if (err) throw err; }); | |
ae510306 | 120 | } |
6cae7b58 | 121 | return; // skip non-javascript files |
ae510306 | 122 | } |
ae510306 | 123 | |
6cae7b58 | 124 | fse.ensureDir(path.dirname(out_path), () => { |
adfc9d3f SR |
125 | if (no_transform_files.has(filename)) { |
126 | console.log(`Writing ${out_path}`); | |
127 | fse.copy(filename, out_path, (err) => { if (err) throw err; }); | |
128 | return; | |
129 | } | |
130 | ||
6cae7b58 SR |
131 | const opts = babel_opts(); |
132 | if (helper && helpers.optionsOverride) { | |
133 | helper.optionsOverride(opts); | |
134 | } | |
1524df89 PO |
135 | // Adjust for the fact that we move the core files relative |
136 | // to the vendor directory | |
a80955ee | 137 | if (vendor_rewrite) { |
1524df89 PO |
138 | opts.plugins.push(["import-redirect", |
139 | {"root": out_path_base, | |
140 | "redirect": { "vendor/(.+)": "./vendor/$1"}}]); | |
141 | } | |
adfc9d3f | 142 | |
d5c5b4aa | 143 | babel.transformFile(filename, opts, (err, res) => { |
6cae7b58 SR |
144 | console.log(`Writing ${out_path}`); |
145 | if (err) throw err; | |
146 | var {code, map, ast} = res; | |
147 | if (source_maps === true) { | |
148 | // append URL for external source map | |
149 | code += `\n//# sourceMappingURL=${path.basename(out_path)}.map\n`; | |
150 | } | |
151 | fs.writeFile(out_path, code, (err) => { if (err) throw err; }); | |
152 | if (source_maps === true || source_maps === 'both') { | |
153 | console.log(` and ${out_path}.map`); | |
154 | fs.writeFile(`${out_path}.map`, JSON.stringify(map), (err) => { if (err) throw err; }); | |
155 | } | |
156 | }); | |
157 | }); | |
158 | }; | |
159 | ||
152c3995 SR |
160 | if (with_app_dir && helper && helper.noCopyOverride) { |
161 | helper.noCopyOverride(paths, no_copy_files); | |
162 | } | |
163 | ||
a80955ee SR |
164 | walkDir(paths.vendor, handleDir.bind(null, true, false, in_path || paths.main), (filename, stats) => !no_copy_files.has(filename)); |
165 | walkDir(paths.core, handleDir.bind(null, true, !in_path, in_path || paths.core), (filename, stats) => !no_copy_files.has(filename)); | |
6cae7b58 SR |
166 | |
167 | if (with_app_dir) { | |
a80955ee | 168 | walkDir(paths.app, handleDir.bind(null, false, false, in_path), (filename, stats) => !no_copy_files.has(filename)); |
6cae7b58 SR |
169 | |
170 | const out_app_path = path.join(out_path_base, 'app.js'); | |
171 | if (helper && helper.appWriter) { | |
172 | console.log(`Writing ${out_app_path}`); | |
173 | let out_script = helper.appWriter(out_path_base, out_app_path); | |
174 | transform_html(out_script); | |
175 | } else { | |
176 | console.error(`Unable to generate app for the ${import_format} format!`); | |
177 | } | |
178 | } | |
ae510306 SR |
179 | }; |
180 | ||
c4e5a50e SR |
181 | if (program.clean) { |
182 | console.log(`Removing ${paths.lib_dir_base}`); | |
183 | fse.removeSync(paths.lib_dir_base); | |
184 | ||
185 | console.log(`Removing ${paths.out_dir_base}`); | |
186 | fse.removeSync(paths.out_dir_base); | |
187 | } | |
188 | ||
6cae7b58 | 189 | make_lib_files(program.as, program.withSourceMaps, program.withApp); |