function minify(page, appNameMap, appContentMap) {
  let cssContent = '';
  let xmlContent = fs.readFileSync(page.wxml, 'utf8');
  if (utils.isFile(page.wxss)) {
    cssContent = fs.readFileSync(page.wxss, 'utf8');
  }
  if (cssContent) {
    cssContent = new CleanCSS({ keepBreaks: true }).minify(cssContent).styles;
    cssContent = cssContent.replace(
      /::?(after|before|first\-child|last\-child)/g,
      ':$1'
    );
  }
  // LESS中存在的className列表
  let styleClassNames = {};
  // LESS中 content -> className 映射
  let pageContentMap = {};
  let finalCssContent = '';
  cssContent.split('\n').forEach(line => {
    let index = line.indexOf('{');
    let selectors = line.substr(0, index).split(',');
    let content = line.substr(index);

    selectors.forEach(selector => {
      if (selector[0] !== '.') {
        finalCssContent += selector + content + '\n';
        return;
      }
      let className = selector.substr(1);
      if (!pageContentMap[content]) {
        pageContentMap[content] = [];
      }
      styleClassNames[className] = true;
      pageContentMap[content].push(className);
      //styles.push({ selector, content, className });
    });
  });
  // console.log('styleClassNames', styleClassNames);
  // console.log('pageContentMap', pageContentMap);
  // console.log('cssContent', cssContent);
  let xmlClassNames = {};
  let clsNameMap = {};
  xmlContent = xmlContent
    .replace(/[\r\n]\s+</g, '\n<')
    .replace(/<!--[^>]+-->/g, '');
  xmlContent = xmlContent.replace(/ class="([^"]+)"/g, (matchs, names) => {
    names = names.replace(/{{([^}]+)}}/g, function(m, words) {
      return '{{' + new Buffer(words, 'utf8').toString('hex') + '}}';
    });
    names = names
      .split(' ')
      .filter(name => {
        if (!name) return false;
        if (name.indexOf('{') > -1) return true;
        if (config.classNames && config.classNames[name]) return true;
        if (appNameMap[name]) {
          appNameMap[name].used = true;
          if (!appNameMap[name].id) {
            appNameMap[name].id = createId();
          }
        }
        if (
          styleClassNames[name] ||
          styleClassNames[name + ':before'] ||
          styleClassNames[name + ':after'] ||
          styleClassNames[name + ':first-child'] ||
          styleClassNames[name + ':last-child'] ||
          appNameMap[name] ||
          appNameMap[name + ':before'] ||
          appNameMap[name + ':after'] ||
          appNameMap[name + ':first-child'] ||
          appNameMap[name + ':last-child']
        ) {
          xmlClassNames[name] = true;
          return true;
        }
        return false;
      })
      .map(function(name) {
        if (name.indexOf('{') > -1) return name;
        if (config.classNames && config.classNames[name]) {
          clsNameMap[name] = name;
          if (appNameMap[name]) {
            appNameMap[name].id = name;
          } else if (
            appNameMap[name + ':before'] ||
            appNameMap[name + ':after'] ||
            appNameMap[name + ':first-child'] ||
            appNameMap[name + ':lasr-child']
          ) {
            // 如果app.less中存在 .name:before 或 .name:after 但是不存在 .name，自动添加 .name
            appNameMap[name] = { id: name, contents: ['{}'] };
          }
          return name;
        }
        if (clsNameMap[name]) {
          return clsNameMap[name];
        }
        let id;
        if (appNameMap[name]) {
          id = appNameMap[name].id;
        } else {
          id = createId();
          // 如果app.less中存在 .name:before 或 .name:after 但是不存在 .name，自动添加 .name
          if (
            appNameMap[name + ':before'] ||
            appNameMap[name + ':after'] ||
            appNameMap[name + ':first-child'] ||
            appNameMap[name + ':last-child']
          ) {
            appNameMap[name] = { id, contents: ['{}'] };
          }
        }
        clsNameMap[name] = id;
        return id;
      });

    if (names.length) {
      // 返回替换后的class name输出到XML中
      return (
        ' class="' +
        names.join(' ').replace(/{{([\da-f]+)}}/g, (m, hex) => {
          return '{{' + new Buffer(hex, 'hex').toString('utf8') + '}}';
        }) +
        '"'
      );
    }
    return '';
  });

  if (cssContent) {
    console.log('minify'.green, path.relative(process.cwd(), page.wxss).blue);
    for (let c in pageContentMap) {
      // c 为样式定义content '{foo:bar}'
      let keys = [];
      pageContentMap[c].forEach(key => {
        // key 为className

        if (appContentMap[c] && appContentMap[c].indexOf(key) > -1) {
          //如果app.wxss中已经存在完全一模一样的记录，则忽略本条
          return;
        }

        let matchs = key.match(/(.*):(after|before|first\-child|last\-child)$/);
        if (matchs && clsNameMap[matchs[1]]) {
          //如果是伪类
          keys.push('.' + clsNameMap[matchs[1]] + ':' + matchs[2]);
          return;
        }

        if (clsNameMap[key]) {
          // 如果页面XML文件中有对应className引用

          keys.push('.' + clsNameMap[key]);
          console.log(('\t.' + key).blue, '->', ('.' + clsNameMap[key]).cyan);
        } else if (config.classNames[key]) {
          // 如果配置文件中要求保留此类名

          keys.push('.' + key);
          console.log(('\t.' + key).blue, '->', ('.' + key).cyan);
        }
      });
      if (keys.length) {
        finalCssContent += keys.join(',') + c + '\n';
      }
    }
  }

  fs.writeFileSync(page.wxml, xmlContent);
  if (finalCssContent) {
    finalCssContent = new CleanCSS({ keepBreaks: true }).minify(finalCssContent)
      .styles;
    fs.writeFileSync(page.wxss, finalCssContent);
  }
}
function minify(page, appNameMap, appContentMap) {
  let cssContent = '';
  let xmlContent = fs.readFileSync(page.wxml, 'utf8');
  if (utils.isFile(page.wxss)) {
    cssContent = fs.readFileSync(page.wxss, 'utf8');
  }
  if (cssContent) {
    cssContent = new CleanCSS({ keepBreaks: true }).minify(cssContent).styles;
    cssContent = cssContent.replace(
      /::?(after|before|first\-child|last\-child)/g,
      ':$1'
    );
  }
  
  let styleClassNames = {};
  
  let pageContentMap = {};
  let finalCssContent = '';
  cssContent.split('\n').forEach(line => {
    let index = line.indexOf('{');
    let selectors = line.substr(0, index).split(',');
    let content = line.substr(index);

    selectors.forEach(selector => {
      if (selector[0] !== '.') {
        finalCssContent += selector + content + '\n';
        return;
      }
      let className = selector.substr(1);
      if (!pageContentMap[content]) {
        pageContentMap[content] = [];
      }
      styleClassNames[className] = true;
      pageContentMap[content].push(className);
      
    });
  });
  
  
  
  let xmlClassNames = {};
  let clsNameMap = {};
  xmlContent = xmlContent
    .replace(/[\r\n]\s+</g, '\n<')
    .replace(/<!--[^>]+-->/g, '');
  xmlContent = xmlContent.replace(/ class="([^"]+)"/g, (matchs, names) => {
    names = names.replace(/{{([^}]+)}}/g, function(m, words) {
      return '{{' + new Buffer(words, 'utf8').toString('hex') + '}}';
    });
    names = names
      .split(' ')
      .filter(name => {
        if (!name) return false;
        if (name.indexOf('{') > -1) return true;
        if (config.classNames && config.classNames[name]) return true;
        if (appNameMap[name]) {
          appNameMap[name].used = true;
          if (!appNameMap[name].id) {
            appNameMap[name].id = createId();
          }
        }
        if (
          styleClassNames[name] ||
          styleClassNames[name + ':before'] ||
          styleClassNames[name + ':after'] ||
          styleClassNames[name + ':first-child'] ||
          styleClassNames[name + ':last-child'] ||
          appNameMap[name] ||
          appNameMap[name + ':before'] ||
          appNameMap[name + ':after'] ||
          appNameMap[name + ':first-child'] ||
          appNameMap[name + ':last-child']
        ) {
          xmlClassNames[name] = true;
          return true;
        }
        return false;
      })
      .map(function(name) {
        if (name.indexOf('{') > -1) return name;
        if (config.classNames && config.classNames[name]) {
          clsNameMap[name] = name;
          if (appNameMap[name]) {
            appNameMap[name].id = name;
          } else if (
            appNameMap[name + ':before'] ||
            appNameMap[name + ':after'] ||
            appNameMap[name + ':first-child'] ||
            appNameMap[name + ':lasr-child']
          ) {
            
            appNameMap[name] = { id: name, contents: ['{}'] };
          }
          return name;
        }
        if (clsNameMap[name]) {
          return clsNameMap[name];
        }
        let id;
        if (appNameMap[name]) {
          id = appNameMap[name].id;
        } else {
          id = createId();
          
          if (
            appNameMap[name + ':before'] ||
            appNameMap[name + ':after'] ||
            appNameMap[name + ':first-child'] ||
            appNameMap[name + ':last-child']
          ) {
            appNameMap[name] = { id, contents: ['{}'] };
          }
        }
        clsNameMap[name] = id;
        return id;
      });

    if (names.length) {
      
      return (
        ' class="' +
        names.join(' ').replace(/{{([\da-f]+)}}/g, (m, hex) => {
          return '{{' + new Buffer(hex, 'hex').toString('utf8') + '}}';
        }) +
        '"'
      );
    }
    return '';
  });

  if (cssContent) {
    console.log('minify'.green, path.relative(process.cwd(), page.wxss).blue);
    for (let c in pageContentMap) {
      
      let keys = [];
      pageContentMap[c].forEach(key => {
        

        if (appContentMap[c] && appContentMap[c].indexOf(key) > -1) {
          
          return;
        }

        let matchs = key.match(/(.*):(after|before|first\-child|last\-child)$/);
        if (matchs && clsNameMap[matchs[1]]) {
          
          keys.push('.' + clsNameMap[matchs[1]] + ':' + matchs[2]);
          return;
        }

        if (clsNameMap[key]) {
          

          keys.push('.' + clsNameMap[key]);
          console.log(('\t.' + key).blue, '->', ('.' + clsNameMap[key]).cyan);
        } else if (config.classNames[key]) {
          

          keys.push('.' + key);
          console.log(('\t.' + key).blue, '->', ('.' + key).cyan);
        }
      });
      if (keys.length) {
        finalCssContent += keys.join(',') + c + '\n';
      }
    }
  }

  fs.writeFileSync(page.wxml, xmlContent);
  if (finalCssContent) {
    finalCssContent = new CleanCSS({ keepBreaks: true }).minify(finalCssContent)
      .styles;
    fs.writeFileSync(page.wxss, finalCssContent);
  }
}
function minify ( page , appNameMap , appContentMap ) { let cssContent = '' ; let xmlContent = fs . readFileSync ( page . wxml , 'utf8' ) ; if ( utils . isFile ( page . wxss ) ) { cssContent = fs . readFileSync ( page . wxss , 'utf8' ) ; } if ( cssContent ) { cssContent = new CleanCSS ( { keepBreaks : true } ) . minify ( cssContent ) . styles ; cssContent = cssContent . replace ( / ::?(after|before|first\-child|last\-child) / g , ':$1' ) ; } // LESS中存在的className列表 let styleClassNames = { } ; // LESS中 content -> className 映射 let pageContentMap = { } ; let finalCssContent = '' ; cssContent . split ( '\n' ) . forEach ( line => { let index = line . indexOf ( '{' ) ; let selectors = line . substr ( 0 , index ) . split ( ',' ) ; let content = line . substr ( index ) ; selectors . forEach ( selector => { if ( selector [ 0 ] !== '.' ) { finalCssContent += selector + content + '\n' ; return ; } let className = selector . substr ( 1 ) ; if ( ! pageContentMap [ content ] ) { pageContentMap [ content ] = [ ] ; } styleClassNames [ className ] = true ; pageContentMap [ content ] . push ( className ) ; //styles.push({ selector, content, className }); } ) ; } ) ; // console.log('styleClassNames', styleClassNames); // console.log('pageContentMap', pageContentMap); // console.log('cssContent', cssContent); let xmlClassNames = { } ; let clsNameMap = { } ; xmlContent = xmlContent . replace ( / [\r\n]\s+< / g , '\n<' ) . replace ( / <!--[^>]+--> / g , '' ) ; xmlContent = xmlContent . replace ( /  class="([^"]+)" / g , ( matchs , names ) => { names = names . replace ( / {{([^}]+)}} / g , function ( m , words ) { return '{{' + new Buffer ( words , 'utf8' ) . toString ( 'hex' ) + '}}' ; } ) ; names = names . split ( ' ' ) . filter ( name => { if ( ! name ) return false ; if ( name . indexOf ( '{' ) > - 1 ) return true ; if ( config . classNames && config . classNames [ name ] ) return true ; if ( appNameMap [ name ] ) { appNameMap [ name ] . used = true ; if ( ! appNameMap [ name ] . id ) { appNameMap [ name ] . id = createId ( ) ; } } if ( styleClassNames [ name ] || styleClassNames [ name + ':before' ] || styleClassNames [ name + ':after' ] || styleClassNames [ name + ':first-child' ] || styleClassNames [ name + ':last-child' ] || appNameMap [ name ] || appNameMap [ name + ':before' ] || appNameMap [ name + ':after' ] || appNameMap [ name + ':first-child' ] || appNameMap [ name + ':last-child' ] ) { xmlClassNames [ name ] = true ; return true ; } return false ; } ) . map ( function ( name ) { if ( name . indexOf ( '{' ) > - 1 ) return name ; if ( config . classNames && config . classNames [ name ] ) { clsNameMap [ name ] = name ; if ( appNameMap [ name ] ) { appNameMap [ name ] . id = name ; } else if ( appNameMap [ name + ':before' ] || appNameMap [ name + ':after' ] || appNameMap [ name + ':first-child' ] || appNameMap [ name + ':lasr-child' ] ) { // 如果app.less中存在 .name:before 或 .name:after 但是不存在 .name，自动添加 .name appNameMap [ name ] = { id : name , contents : [ '{}' ] } ; } return name ; } if ( clsNameMap [ name ] ) { return clsNameMap [ name ] ; } let id ; if ( appNameMap [ name ] ) { id = appNameMap [ name ] . id ; } else { id = createId ( ) ; // 如果app.less中存在 .name:before 或 .name:after 但是不存在 .name，自动添加 .name if ( appNameMap [ name + ':before' ] || appNameMap [ name + ':after' ] || appNameMap [ name + ':first-child' ] || appNameMap [ name + ':last-child' ] ) { appNameMap [ name ] = { id , contents : [ '{}' ] } ; } } clsNameMap [ name ] = id ; return id ; } ) ; if ( names . length ) { // 返回替换后的class name输出到XML中 return ( ' class="' + names . join ( ' ' ) . replace ( / {{([\da-f]+)}} / g , ( m , hex ) => { return '{{' + new Buffer ( hex , 'hex' ) . toString ( 'utf8' ) + '}}' ; } ) + '"' ) ; } return '' ; } ) ; if ( cssContent ) { console . log ( 'minify' . green , path . relative ( process . cwd ( ) , page . wxss ) . blue ) ; for ( let c in pageContentMap ) { // c 为样式定义content '{foo:bar}' let keys = [ ] ; pageContentMap [ c ] . forEach ( key => { // key 为className if ( appContentMap [ c ] && appContentMap [ c ] . indexOf ( key ) > - 1 ) { //如果app.wxss中已经存在完全一模一样的记录，则忽略本条 return ; } let matchs = key . match ( / (.*):(after|before|first\-child|last\-child)$ / ) ; if ( matchs && clsNameMap [ matchs [ 1 ] ] ) { //如果是伪类 keys . push ( '.' + clsNameMap [ matchs [ 1 ] ] + ':' + matchs [ 2 ] ) ; return ; } if ( clsNameMap [ key ] ) { // 如果页面XML文件中有对应className引用 keys . push ( '.' + clsNameMap [ key ] ) ; console . log ( ( '\t.' + key ) . blue , '->' , ( '.' + clsNameMap [ key ] ) . cyan ) ; } else if ( config . classNames [ key ] ) { // 如果配置文件中要求保留此类名 keys . push ( '.' + key ) ; console . log ( ( '\t.' + key ) . blue , '->' , ( '.' + key ) . cyan ) ; } } ) ; if ( keys . length ) { finalCssContent += keys . join ( ',' ) + c + '\n' ; } } } fs . writeFileSync ( page . wxml , xmlContent ) ; if ( finalCssContent ) { finalCssContent = new CleanCSS ( { keepBreaks : true } ) . minify ( finalCssContent ) . styles ; fs . writeFileSync ( page . wxss , finalCssContent ) ; } }
压缩页面
@param {Object} page
@param {Object} appNameMap
@param {Object} appContentMap
压缩页面