UNPKG

6.77 kBPlain TextView Raw
1import rollup_cjs from '@rollup/plugin-commonjs';
2import rollup_multi from '@rollup/plugin-multi-entry';
3import rollup_re from '@rollup/plugin-node-resolve';
4import { saferRemove } from 'backlib';
5import * as fs from 'fs-extra';
6/////// for handlebars
7import { precompile as hbsPrecompile } from 'hbsp'; // promise style
8import * as Path from 'path';
9//////// for Postcss
10import postcss from "postcss";
11/////// for JS
12import * as rollup from 'rollup';
13import rollup_ts from 'rollup-plugin-typescript2'; // TODO: might want to update to @rollup/plugin-typescript (But it is a different implementation)
14import { now } from './utils';
15
16const processors = [
17 require("autoprefixer"),
18 require("postcss-import"),
19 require("postcss-mixins"),
20 require("postcss-nested")
21];
22
23// --------- For Handlebars --------- //
24export async function tmplFiles(files: string[], distFile: string) {
25
26 await saferRemove([distFile]);
27
28 const templateContent = [];
29
30 for (let file of files) {
31
32 const htmlTemplate = await fs.readFile(file, "utf8");
33 const template = await hbsPrecompile(file, htmlTemplate);
34 templateContent.push(template);
35 }
36
37 await fs.writeFile(distFile, templateContent.join("\n"), "utf8");
38}
39// --------- /For Handlebars --------- //
40
41// --------- For postCss --------- //
42export async function pcssFiles(entries: string[], distFile: string) {
43
44 const mapFile = distFile + ".map";
45 let pcssResult: any;
46 try {
47
48 await saferRemove([distFile, mapFile]);
49
50 const processor = postcss(processors);
51 const pcssNodes = [];
52
53 // we parse all of the .pcss files
54 for (let srcFile of entries) {
55 // read the file
56 let pcss = await fs.readFile(srcFile, "utf8");
57
58 const pcssNode = postcss.parse(pcss, {
59 from: srcFile
60 });
61 pcssNodes.push(pcssNode);
62
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.toString(), "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");
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);
123 }
124 await saferRemove(mapFile);
125 } catch (ex) {
126 console.log(`Can't delete dist files`, ex);
127 }
128
129
130 // set the default rollup input options
131 const inputOptions: any = {
132 input: entries,
133 plugins: [rollup_multi(), rollup_cjs(), rollup_re()]
134 };
135
136 // --------- Exclude 3rd Party circular Dependencies --------- //
137 const excludeCircularWarningByImporters = ['node_modules/d3', 'node_modules/moment'];
138 inputOptions.onwarn = function onwarn(warning: any) {
139 let skip = false;
140
141 if (warning.code === 'CIRCULAR_DEPENDENCY') {
142 for (let skipImporter of excludeCircularWarningByImporters) {
143 if (warning.importer.startsWith(skipImporter)) {
144 skip = true;
145 break;
146 }
147 }
148 }
149 // NOTE: 2019-01-10 for now skip the plugin warning because of ONGENERATE_HOOK_DEPRECATED on rpt2
150 if (warning.code === 'PLUGIN_WARNING') {
151 skip = true;
152 }
153
154 if (!skip) {
155 console.log(`rollup warning - ${warning.message}`);
156 }
157 };
158 // --------- /Exclude 3rd Party circular Dependencies --------- //
159
160 // set the default rollup output options
161 // make the name from file name "web/js/lib-bundle.js" : "lib_bundle"
162 const name = Path.parse(distFile).name.replace(/\W+/g, "_");
163 const outputOptions: any = {
164 file: distFile,
165 format: 'iife',
166 name,
167 sourcemap: true,
168 sourcemapFile: mapFile
169 };
170
171 // if ts, then, we add the rollup_ts plugin
172 if (opts.ts || opts.tsconfig) {
173 let tsOpts: any = {
174 clean: true
175 };
176 if (opts.tsconfig) {
177 tsOpts.tsconfig = opts.tsconfig;
178 }
179 // Note: if we do not have clean:true, we get some exception when watch.
180 inputOptions.plugins.push(rollup_ts(tsOpts));
181 }
182
183 // if we have some globals, we add them accordingly
184 if (opts.globals) {
185 // for input, just set the external (clone to be safe(r))
186 inputOptions.external = Object.keys(opts.globals);
187 outputOptions.globals = opts.globals;
188 }
189
190 try {
191 // if it is watch mode, we do the watch
192 if (opts.watch) {
193 //wathOptions = { inputOptions };
194 let watchOptions = { ...inputOptions };
195 watchOptions.output = outputOptions;
196 watchOptions.watch = { chokidar: true };
197
198 const watcher = rollup.watch(watchOptions);
199 let startTime: number;
200
201 watcher.on('event', async function (evt) {
202 // console.log('rollup watch', evt.code, evt.output);
203 if (evt.code === 'START') {
204 startTime = now();
205 } else if (evt.code === 'END') {
206 let size = (await fs.stat(distFile)).size;
207 size = Math.round(size / 1000.0);
208 console.log(`Recompile ${distFile} - ${Math.round(now() - startTime)}ms - ${size} kb`);
209 } else if (evt.code === 'ERROR') {
210 console.log(`ERROR - Rollup/Typescript error when processing: ${distFile}`);
211 console.log("\t" + 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