UNPKG

6.76 kBPlain TextView Raw
1import { now, saferRemove } from './utils';
2import * as Path from 'path';
3import * as fs from 'fs-extra-plus';
4
5//////// for Postcss
6const postcss = require("postcss");
7const processors = [
8 require("autoprefixer"),
9 require("postcss-import"),
10 require("postcss-mixins"),
11 require("postcss-nested")
12];
13
14/////// for JS
15import * as rollup from 'rollup';
16import rollup_cjs = require('rollup-plugin-commonjs');
17import rollup_re = require('rollup-plugin-node-resolve');
18import rollup_ts = require('rollup-plugin-typescript2');
19import rollup_multi = require('rollup-plugin-multi-entry');
20
21/////// for handlebars
22import { precompile as hbsPrecompile } from 'hbsp'; // promise style
23
24// --------- For Handlebars --------- //
25export async function tmplFiles(files: string[], distFile: string) {
26
27 await fs.saferRemove([distFile]);
28
29 const templateContent = [];
30
31 for (let file of files) {
32
33 const htmlTemplate = await fs.readFile(file, "utf8");
34 const template = await hbsPrecompile(file, htmlTemplate);
35 templateContent.push(template);
36 }
37
38 await fs.writeFile(distFile, templateContent.join("\n"), "utf8");
39}
40// --------- /For Handlebars --------- //
41
42// --------- For postCss --------- //
43export async function pcssFiles(entries: string[], distFile: string) {
44
45 const mapFile = distFile + ".map";
46 let pcssResult: any;
47 try {
48
49 await fs.saferRemove([distFile, mapFile]);
50
51 const processor = postcss(processors);
52 const pcssNodes = [];
53
54 // we parse all of the .pcss files
55 for (let srcFile of entries) {
56 // read the file
57 let pcss = await fs.readFile(srcFile, "utf8");
58
59 const pcssNode = postcss.parse(pcss, {
60 from: srcFile
61 });
62 pcssNodes.push(pcssNode);
63 }
64
65 // build build the combined rootNode and its result
66 let rootNode = null;
67 for (let pcssNode of pcssNodes) {
68 rootNode = (rootNode) ? rootNode.append(pcssNode) : pcssNode;
69 }
70 const rootNodeResult = rootNode.toResult();
71
72 // we process the rootNodeResult
73 pcssResult = await processor.process(rootNodeResult, {
74 from: "undefined",
75 to: distFile,
76 map: { inline: false }
77 });
78 } catch (ex) {
79 console.log(`postcss ERROR - Cannot process ${distFile} because (setting css empty file) \n${ex}`);
80 // we write the .css and .map files
81 await fs.writeFile(distFile, "", "utf8");
82 await fs.writeFile(mapFile, "", "utf8");
83 return;
84 }
85
86 // we write the .css and .map files
87 await fs.writeFile(distFile, pcssResult.css, "utf8");
88 await fs.writeFile(mapFile, pcssResult.map, "utf8");
89}
90// --------- /For postCss --------- //
91
92
93// --------- For Rollup (JavaScript) --------- //
94export interface RollupFilesOptions {
95 ts?: boolean;
96 /* {importName: globalName} - (default undefined) define the list of global names (assumed to be mapped to window._name_) */
97 globals?: { [importName: string]: string };
98 watch: boolean;
99 tsconfig?: any;
100}
101const defaultOpts: RollupFilesOptions = {
102 ts: true,
103 watch: false
104};
105
106/**
107 * @param {*} opts
108 * - ts?: boolean - (default true)
109 * -
110 * - watch: true | false (default false)
111 */
112export async function rollupFiles(entries: string[], distFile: string, opts: RollupFilesOptions) {
113 opts = Object.assign({}, defaultOpts, opts);
114
115 await saferRemove("./.rpt2_cache", false);
116
117 // delete the previous ouutput files
118 const mapFile = distFile + ".map";
119 try {
120 // Note: Do not delete the distFile if we are in watch mode, otherwise, rollup throw an uncatched promise exception
121 if (!opts.watch) {
122 await saferRemove(distFile, false);
123 }
124 await saferRemove(mapFile, false);
125 } catch (ex) {
126 console.log(`Can't delete dist files`, ex);
127 }
128
129 // set the default rollup input options
130 const inputOptions: any = {
131 input: entries,
132 plugins: [rollup_multi(), rollup_cjs(), rollup_re()]
133 };
134
135 // --------- Exclude 3rd Party circular Dependencies --------- //
136 const excludeCircularWarningByImporters = ['node_modules/d3'];
137 inputOptions.onwarn = function onwarn(warning: any) {
138 let skip = false;
139
140 if (warning.code === 'CIRCULAR_DEPENDENCY') {
141 for (let skipImporter of excludeCircularWarningByImporters) {
142 if (warning.importer.startsWith(skipImporter)) {
143 skip = true;
144 break;
145 }
146 }
147 }
148 // NOTE: 2019-01-10 for now skip the plugin warning because of ONGENERATE_HOOK_DEPRECATED on rpt2
149 if (warning.code === 'PLUGIN_WARNING') {
150 skip = true;
151 }
152
153 if (!skip) {
154 console.log(`rollup warning - ${warning.message}`);
155 }
156 };
157 // --------- /Exclude 3rd Party circular Dependencies --------- //
158
159 // set the default rollup output options
160 // make the name from file name "web/js/lib-bundle.js" : "lib_bundle"
161 const name = Path.parse(distFile).name.replace(/\W+/g, "_");
162 const outputOptions: any = {
163 file: distFile,
164 format: 'iife',
165 name,
166 sourcemap: true,
167 sourcemapFile: mapFile
168 };
169
170 // if ts, then, we add the rollup_ts plugin
171 if (opts.ts || opts.tsconfig) {
172 let tsOpts: any = {
173 clean: true
174 };
175 if (opts.tsconfig) {
176 tsOpts.tsconfig = opts.tsconfig;
177 }
178 // Note: if we do not have clean:true, we get some exception when watch.
179 inputOptions.plugins.push(rollup_ts(tsOpts));
180 }
181
182 // if we have some globals, we add them accordingly
183 if (opts.globals) {
184 // for input, just set the external (clone to be safe(r))
185 inputOptions.external = Object.keys(opts.globals);
186 outputOptions.globals = opts.globals;
187 }
188
189 try {
190 // if it is watch mode, we do the watch
191 if (opts.watch) {
192 //wathOptions = { inputOptions };
193 let watchOptions = { ...inputOptions };
194 watchOptions.output = outputOptions;
195 watchOptions.watch = { chokidar: true };
196
197 const watcher = rollup.watch(watchOptions);
198 let startTime: number;
199
200 watcher.on('event', function (evt) {
201 // console.log('rollup watch', evt.code, evt.output);
202 if (evt.code === 'START') {
203 startTime = now();
204 } else if (evt.code === 'END') {
205 console.log(`Recompile ${distFile} done: ${Math.round(now() - startTime)}ms`);
206 } else if (evt.code === 'ERROR') {
207 console.log(`ERROR - Rollup/Typescript error when processing: ${distFile}`);
208 console.log("\t" + evt.error);
209 } else if (evt.code === 'FATAL') {
210 console.log(`FATAL ERROR - Rollup/Typescript fatal error when processing ${distFile}\n
211 >>>>>>>> MUST RESTART WATCH SESSION <<<<<<<<\n\n`, evt.error);
212 }
213
214 });
215
216
217 }
218 // otherwise, we do the full build
219 else {
220 // bundle
221 const bundle = await rollup.rollup(inputOptions);
222
223 // write
224 await bundle.write(outputOptions);
225 }
226
227
228 // make sure the .rpt2_cache/ folder is delete (apparently, clean:true does not work)
229 //await fs.remove("./.rpt2_cache");
230 } catch (ex) {
231 // make sure we write nothing in the file, to know nothing got compiled and fail early
232 await fs.writeFile(distFile, "", "utf8");
233 throw ex;
234 }
235}
236// --------- /For Rollup (JavaScript) --------- //
237
238