index.js 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. const { JSDOM } = require('jsdom');
  2. const fs = require('fs')
  3. const path = require('path')
  4. const request = require('request')
  5. const UglifyJS = require("uglify-js");
  6. const CleanCSS = require('clean-css');
  7. const minifyHtml = require('html-minifier').minify
  8. /**
  9. * 抽取所有脚本css等文件
  10. * @param {Document} document jsdom
  11. */
  12. function scriptFilter(document) {
  13. let ret = {script: [], link: []}
  14. for (let i = 0, dom = document.querySelectorAll('script'); i < dom.length; i++) {
  15. let src = dom[i].getAttribute('src')
  16. ret.script.push(src ?
  17. {content: src, type: 1, url: src} :
  18. {content: dom[i].innerHTML, type: 0, url: src}
  19. )
  20. dom[i].parentNode.removeChild(dom[i]);
  21. }
  22. for (let i = 0, dom = document.querySelectorAll('link[rel="stylesheet"],style'); i < dom.length; i++) {
  23. let tagName = dom[i].tagName
  24. ret.link.push(tagName === 'LINK' ?
  25. {content: dom[i].getAttribute('href'), type: 1} :
  26. {content: dom[i].innerHTML, type: 0}
  27. )
  28. dom[i].parentNode.removeChild(dom[i]);
  29. }
  30. return ret
  31. }
  32. /**
  33. * 下载所有资源
  34. * @param {String} dir 文件所在的路径
  35. * @param {Array} contents 文件
  36. */
  37. async function downContent(dir, contents) {
  38. let labels = ['script', 'link']
  39. for (let i = 0, label; label = labels[i]; i++) {
  40. for (let j = 0, item; item = contents[label][j]; j++) {
  41. if (item.type === 1) {
  42. let src = path.join(dir, item.content)
  43. src = ~src.indexOf('?') ? src.substring(0, src.indexOf('?')) : src
  44. if (fs.existsSync(src)) {
  45. item.content = fs.readFileSync(src).toString()
  46. } else {
  47. await new Promise(resolve => {
  48. request.get(item.content, (err, response) => {
  49. if (!err && response.statusCode === 200) {
  50. item.content = response.body
  51. } else {
  52. item.content = ''
  53. }
  54. resolve()
  55. })
  56. });
  57. }
  58. }
  59. }
  60. }
  61. return contents
  62. }
  63. /**
  64. * 合并资源,并压缩
  65. * @param {JSON} contents 所有资源
  66. */
  67. function mergeStatic (contents) {
  68. let ret = {script: '', link: ''}
  69. Object.keys(ret).forEach(label => {
  70. contents[label].forEach(item => {
  71. ret[label] += item.content
  72. label === 'script' && (ret[label] += ';')
  73. })
  74. })
  75. ret.script = UglifyJS.minify(ret.script, {
  76. compress: {
  77. dead_code: true,
  78. global_defs: {
  79. DEBUG: false
  80. }
  81. }
  82. }).code
  83. ret.link = new CleanCSS({}).minify(ret.link).styles
  84. return ret
  85. }
  86. async function main (file) {
  87. let src = path.join(process.cwd(), file)
  88. console.log(src)
  89. let document = new JSDOM(fs.readFileSync(src)).window.document
  90. let dir = path.join(src, '../')
  91. let contents = await downContent(
  92. path.join(src, '../'),
  93. scriptFilter(document)
  94. )
  95. let ret = mergeStatic(contents)
  96. let $script = document.createElement('script')
  97. let $link = document.createElement('link')
  98. $script.setAttribute('src', 'js/minify-script.js')
  99. $link.setAttribute('rel', 'stylesheet')
  100. $link.setAttribute('href', 'css/minify-style.css')
  101. document.head.appendChild($link)
  102. document.body.appendChild($script)
  103. let html = `
  104. <!doctype html>
  105. <html>
  106. ${document.documentElement.innerHTML}
  107. </html>
  108. `
  109. fs.writeFileSync(path.join(dir, 'js/minify-script.js'), ret.script)
  110. fs.writeFileSync(path.join(dir, 'css/minify-style.css'), ret.link)
  111. fs.writeFileSync(path.join(dir, 'minify-temp.html'), minifyHtml(html, {
  112. removeComments: true,
  113. collapseWhitespace: true,
  114. }))
  115. }
  116. main(...process.argv.splice(2))