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 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 | 1× 1× 1× 1× 1× 1× 1× 1× 64× 64× 64× 64× 64× 64× 64× 64× 1× 63× 63× 63× 189× 118× 71× 71× 71× 71× 43× 71× 63× 391× 64× 64× 64× 71× 64× 64× 64× 64× 64× 39× 64× 64× 64× 71× 71× 28× 34× 71× 43× 71× 64× 64× 64× 64× 64× 71× 71× 71× 64× 64× 64× 64× 64× 64× 64× 64× 64× 64× 64× 1× 1× 71× 71× 71× 71× 71× | "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); const template_api_1 = require("@opticss/template-api"); const Concat = require("concat-with-sourcemaps"); const postcss = require("postcss"); const initializers_1 = require("./initializers"); const OpticssOptions_1 = require("./OpticssOptions"); const OptimizationPass_1 = require("./OptimizationPass"); const optimizations_1 = require("./optimizations"); class Optimizer { /** * Creates a new OptiCSS Optimizer. * * @param sources a list of css files to be optimized. * within a given css file, the cascade is respected as a conflict resolution * signal. Classes from multiple files are assumed to have an arbitrary ordering * and the cascade is not used to resolve conflicts between properties. Instead, * those conflicts must be resolvable by having analysis information that proves * they don't conflict or by having selectors that unambiguously resolve the conflict. */ constructor(options, templateOptions) { this.sources = []; this.analyses = []; // TODO: give an error if the options conflict with the template integration abilities? this.options = Object.assign({}, OpticssOptions_1.DEFAULT_OPTIONS, options); this.templateOptions = template_api_1.normalizeTemplateOptions(templateOptions); this.optimizations = new Set(); this.initializers = new Set(); this.timings = {}; // If disabled, short circuit. if (!this.options.enabled) { return; } // Load all Initializers and optimizations alloed by template and app options. let only = this.options.only || []; let except = this.options.except || []; Object.keys(optimizations_1.optimizations).forEach(opt => { // If optimization is excluded by the `only` or `except` options, skip it. if ((only.length && !only.includes(opt)) || (except.length && except.includes(opt))) { return; } // If this optimization is included by config, add it and its initializers to our list. Eif (this.options[opt]) { let optimization = new optimizations_1.optimizations[opt](this.options, this.templateOptions); this.optimizations.add(optimization); for (let initializerName of optimization.initializers) { this.initializers.add(initializerName); } } }); } /** * Add another source file to include in this optimization. * @param CSS File to add */ addSource(file) { this.sources.push(file); } /** * Add another TemplateAnalysis to use in this optimization. * @param TemplateAnalysis to use. */ addAnalysis(analysis) { this.analyses.push(analysis); } /** * Utility method to save timing data. * @param Timing measurement name. * @param Timing measurement start. * @param Timing measurement end. */ logTiming(name, start, end) { this.timings[name] = { start: start.getUTCMilliseconds(), end: end.getUTCMilliseconds(), }; } /** * Parse all CSS files this optimizer is concerned with. * @param All sources registered with this Optimizer. * @returns All files we're working on, now represented as postcss trees. */ parseFiles(sources) { let start = new Date(); let promises = new Array(); for (let source of sources) { promises.push(parseCss(source)); } return Promise.all(promises).then((res) => { this.logTiming("parse", start, new Date()); return res; }); } /** * Run all optimizations' initializers. * @param This optimization pass instance. * @param All files we're working on, parsed as postcss trees. */ initialize(pass, files) { let start = new Date(); this.initializers.forEach(initializerName => { initializers_1.initializers[initializerName](pass, this.analyses, files, this.options, this.templateOptions); }); this.logTiming("initialize", start, new Date()); } /** * Run all of this optimizer's optimizations. * @param This optimization pass instance. * @param All files we're working on, parsed as postcss trees. * @returns All the files we're just transformed. */ optimizeFiles(pass, files) { let begin = new Date(); this.optimizations.forEach((optimization) => { let start = new Date(); if (optimizations_1.isSingleFileOptimization(optimization)) { for (let file of files) { optimization.optimizeSingleFile(pass, this.analyses, file); } } if (optimizations_1.isMultiFileOptimization(optimization)) { optimization.optimizeAllFiles(pass, this.analyses, files); } this.logTiming(optimization.name, start, new Date()); }); this.logTiming("optimize", begin, new Date()); return Promise.resolve(files); } /** * Concatenate all of this Optimizer's files into a single output. * @param All postcss ASTs we're working on. * @param The expected output's filename. * @returns The concatenated file. */ concatenateFiles(files, outputFilename) { let start = new Date(); let output = new Concat(true, outputFilename, "\n"); for (let file of files) { let resultOpts = { to: outputFilename, map: { inline: false, prev: file.content.map, sourcesContent: true, annotation: false, }, }; let result = file.content.root.toResult(resultOpts); output.add(file.filename || "optimized-input.css", result.css, result.map.toJSON()); } this.logTiming("concatenate", start, new Date()); return output; } /** * Main runner method for the Optimizer. After all Sources and Analyses are registered, * calling this method executes all requested optimizations and returns an optimization result. * @param outputFilename - The output's filename. The file is not written * but it is needed to ensure that source maps works correctly. * @returns The optimization result. */ optimize(outputFilename) { let pass = new OptimizationPass_1.OptimizationPass(this.options, this.templateOptions); let start = new Date(); // Parse all input files. return this.parseFiles(this.sources) // Run all initializers on parsed files. .then(files => { this.initialize(pass, files); return files; }) // Run all optimizers on parsed files. .then(files => { return this.optimizeFiles(pass, files); }) // Concatenate all files and return optimization result. .then((files) => { let output = this.concatenateFiles(files, outputFilename); this.logTiming("total", start, new Date()); return { output: { filename: outputFilename, content: output.content.toString(), sourceMap: output.sourceMap, }, styleMapping: pass.styleMapping, actions: pass.actions, }; }); } } exports.Optimizer = Optimizer; /** * Given a CssFile (contents represented as a string), return the ParsedCssFile (contents represented as a postcss AST. * @param Input CssFile. * @returns The ParsedCssFile. */ function parseCss(file) { Eif (typeof file.content === "string") { return new Promise((resolve, reject) => { let processOpts = { from: file.filename, map: { inline: false, prev: file.sourceMap, sourcesContent: true, annotation: false, }, }; postcss().process(file.content, processOpts).then(resolve, reject); }).then(result => { return { content: result, filename: file.filename, }; }); } else { return Promise.resolve(file); } } //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiT3B0aW1pemVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL09wdGltaXplci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLHdEQU0rQjtBQUMvQixpREFBa0Q7QUFDbEQsbUNBQW1DO0FBSW5DLGlEQUE0RDtBQUM1RCxxREFBbUU7QUFDbkUseURBQXNEO0FBQ3RELG1EQUt5QjtBQWV6QjtJQWdCRTs7Ozs7Ozs7O09BU0c7SUFDSCxZQUFZLE9BQWdDLEVBQUUsZUFBb0Q7UUFDaEcsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFDbEIsSUFBSSxDQUFDLFFBQVEsR0FBRyxFQUFFLENBQUM7UUFDbkIsdUZBQXVGO1FBQ3ZGLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUFFLEVBQUUsZ0NBQWUsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUMzRCxJQUFJLENBQUMsZUFBZSxHQUFHLHVDQUF3QixDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ2pFLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUMvQixJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7UUFDOUIsSUFBSSxDQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7UUFFbEIsOEJBQThCO1FBQzlCLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRTtZQUFFLE9BQU87U0FBRTtRQUV0Qyw4RUFBOEU7UUFDOUUsSUFBSSxJQUFJLEdBQWEsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQzdDLElBQUksTUFBTSxHQUFhLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxJQUFJLEVBQUUsQ0FBQztRQUNqRCxNQUFNLENBQUMsSUFBSSxDQUFDLDZCQUFhLENBQUMsQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUU7WUFFdkMsMEVBQTBFO1lBQzFFLElB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 |