| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118 |
- const U2 = require("uglify-js");
- const htmlMinify = require('html-minifier').minify;
- const CleanCSS = require('clean-css');
- const svgo = require('svgo');
- const convert = require('xml-js');
- defaultOptions = {
- collapseWhitespace: true,
- minifyCSS:true,
- minifySVG:true,
- svgOptions:{
- plugins: svgo.extendDefaultPlugins([
- {
- name: 'removeViewBox',
- active: false
- }
- ]),
- }
- }
- /**
- * Extract element containing token to Cdata element
- * @param {string} token
- * @param {XMLElement} elt
- * @returns {XMLElement} tranform XML tree by stringifying element containing the token
- */
- const toCData = function(elt,token){
- let transform = elt.name == token;
- if(elt.type=="text" && elt.text.includes(token)){
- transform = true
- }else if ("attributes" in elt ){
- for (const k of Object.keys(elt.attributes)) {
- if (k.includes(token)){
- transform = true;
- }else if(elt.attributes[k].includes(token)){
- transform = true
- }
- if(transform){
- break
- }
- }
- }
- if (transform){
- const newElt = {
- type:"cdata",
- cdata:token + JSON.stringify(elt)
- }
- return newElt
- }else{
- if ('elements' in elt){
- elt.elements = elt.elements.map(e=>toCData(e,token))
- }
- return elt
- }
- }
- /**
- * Recover extracted element containing token from Cdata element
- * @param {string} token
- * @param {XMLElement} elt
- * @returns {XMLElement} restored XML tree
- */
- const fromCData = function(elt,token){
- if (elt.type == "cdata" && elt.cdata.startsWith(token)){
- return JSON.parse(elt.cdata.substr(token.length))
- }else{
- if ('elements' in elt){
- elt.elements = elt.elements.map(e=>fromCData(e,token))
- }
- return elt
- }
- }
- module.exports = function (code, options){
- let mergedOptions = {...defaultOptions, ...options}
- const ast = U2.parse(code)
- let cssOptions = false;
- if (mergedOptions.minifyCSS){
- cssOptions = typeof mergedOptions.minifyCSS == 'object' ? mergedOptions.minifyCSS:{}
- }
- let svgOptions = false;
- if (mergedOptions.minifySVG){
- svgOptions = mergedOptions.svgOptions ? mergedOptions.svgOptions : {};
- }
- ast.walk(new U2.TreeWalker( (node)=>{
- if (node instanceof U2.AST_Template && node.tag && ['html','css','svg'].includes(node.tag.name)){
- const templateContent = node.strings.map(s=>s.replace(/[\n|\r]/gm, ' '))
- if(node.tag.name =="html"){
- const input = templateContent.join('${}');
- const output = htmlMinify(input, mergedOptions)
- node.strings = output.split("${}");
- } else if(node.tag.name == "css" && cssOptions){
- if (templateContent.length>1){
- throw new Error("css literal cannot use template.\r\nMore info https://lit-element.polymer-project.org/api/modules/_lit_element_.html#css ")
- }
- const input = templateContent[0];
- const output = new CleanCSS(cssOptions).minify(input).styles
- node.strings = [output];
- } else if(node.tag.name == "svg" && svgOptions){
- const token = 'validTokenMlet'
- const input = templateContent.join(token);
- // Parse XML
- let obj = convert.xml2js(input)
- // Transform elements containing template to CData elt
- obj = toCData(obj, token)
- // Optimise svg (it does not affect Cdata elements)
- let xml = convert.js2xml(obj);
- xml = svgo.optimize(xml, svgOptions).data
- // Revert CData elt to their original form
- obj = convert.xml2js(xml)
- obj = fromCData(obj,token)
- // Reconstruct template
- node.strings = convert.js2xml(obj).split(token);
- }
- }
- }))
- return ast.print_to_string({ beautify: false });;
- }
|