index.js 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. /**
  2. * FeHelper Code Compress
  3. */
  4. let editor = {};
  5. new Vue({
  6. el: '#pageContainer',
  7. data: {
  8. codeType: 'html',
  9. sourceContent: '',
  10. resultContent: '',
  11. hasError: false,
  12. compressInfo: ''
  13. },
  14. mounted: function () {
  15. editor = CodeMirror.fromTextArea(this.$refs.codeSource, {
  16. mode: "htmlmixed",
  17. lineNumbers: true,
  18. matchBrackets: true,
  19. styleActiveLine: true,
  20. lineWrapping: true
  21. });
  22. //输入框聚焦
  23. editor.focus();
  24. },
  25. methods: {
  26. compress: function () {
  27. this.hasError = false;
  28. this.compressInfo = '';
  29. this.sourceContent = editor.getValue().trim();
  30. if (!this.sourceContent) {
  31. alert('请先粘贴您需要压缩的代码');
  32. } else {
  33. if (this.codeType === 'js') {
  34. this.jsCompress(this.sourceContent);
  35. } else if (this.codeType === 'css') {
  36. this.cssCompress(this.sourceContent);
  37. } else {
  38. this.htmlCompress(this.sourceContent);
  39. }
  40. }
  41. },
  42. changeCodeType(ctype) {
  43. let editorMode = {
  44. css: 'text/css',
  45. js: {name: 'javascript', json: true},
  46. html: 'htmlmixed'
  47. };
  48. editor.setOption('mode', editorMode[ctype]);
  49. if (editor.getValue().trim()) {
  50. this.$nextTick(this.compress);
  51. }
  52. },
  53. buildCompressInfo(original, minified) {
  54. let commify = str => String(str).split('').reverse().join('').replace(/(...)(?!$)/g, '$1,').split('').reverse().join('');
  55. let diff = original.length - minified.length;
  56. let savings = original.length ? (100 * diff / minified.length).toFixed(2) : 0;
  57. this.compressInfo = '压缩前: <strong>' + commify(original.length) + '</strong>' +
  58. ',压缩后: <strong>' + commify(minified.length) + '</strong>' +
  59. ',压缩率: <strong>' + commify(diff) + ' (' + savings + '%)</strong>';
  60. },
  61. jsCompress(js) {
  62. // 判断是否为合法JSON,如果是则加t=前缀后用UglifyJS压缩,压缩后去掉t=前缀
  63. let isJSON = false;
  64. let jsonStr = js.trim();
  65. let result;
  66. try {
  67. if ((jsonStr.startsWith('{') || jsonStr.startsWith('[')) && (jsonStr.endsWith('}') || jsonStr.endsWith(']'))) {
  68. JSON.parse(jsonStr);
  69. isJSON = true;
  70. }
  71. } catch (e) {
  72. isJSON = false;
  73. }
  74. if (isJSON) {
  75. // 加t=前缀
  76. let jsWithPrefix = 't=' + jsonStr;
  77. result = UglifyJs3.compress(jsWithPrefix);
  78. this.hasError = !!result.error;
  79. if (!this.hasError && result.out.startsWith('t=')) {
  80. this.resultContent = result.out.substring(2); // 去掉t=
  81. } else {
  82. this.resultContent = result.out || result.error;
  83. }
  84. !this.hasError && this.buildCompressInfo(this.sourceContent, this.resultContent);
  85. return;
  86. }
  87. // 原有JS压缩逻辑
  88. result = UglifyJs3.compress(js);
  89. this.hasError = !!result.error;
  90. this.resultContent = result.out || result.error;
  91. !this.hasError && this.buildCompressInfo(this.sourceContent, this.resultContent);
  92. },
  93. cssCompress(css) {
  94. let res = css.replace(/\/\*(.|\n)*?\*\//g, "")
  95. .replace(/\s*([\{\}\:\;\,])\s*/g, "$1")
  96. .replace(/\,[\s\.\#\d]*\{/g, "{")
  97. .replace(/;\s*;/g, ";")
  98. .match(/^\s*(\S+(\s+\S+)*)\s*$/);
  99. this.resultContent = (res === null) ? css : res[1];
  100. this.buildCompressInfo(this.sourceContent, this.resultContent);
  101. },
  102. htmlCompress(html) {
  103. let options = {
  104. "caseSensitive": false,
  105. "collapseBooleanAttributes": true,
  106. "collapseInlineTagWhitespace": false,
  107. "collapseWhitespace": true,
  108. "conservativeCollapse": false,
  109. "decodeEntities": true,
  110. "html5": true,
  111. "includeAutoGeneratedTags": false,
  112. "keepClosingSlash": false,
  113. "minifyCSS": true,
  114. "minifyJS": true,
  115. "preserveLineBreaks": false,
  116. "preventAttributesEscaping": false,
  117. "processConditionalComments": true,
  118. "processScripts": ["text/html"],
  119. "removeAttributeQuotes": true,
  120. "removeComments": true,
  121. "removeEmptyAttributes": true,
  122. "removeEmptyElements": false,
  123. "removeOptionalTags": true,
  124. "removeRedundantAttributes": true,
  125. "removeScriptTypeAttributes": true,
  126. "removeStyleLinkTypeAttributes": true,
  127. "removeTagWhitespace": true,
  128. "sortAttributes": true,
  129. "sortClassName": true,
  130. "trimCustomFragments": true,
  131. "useShortDoctype": true
  132. };
  133. options.log = console.log;
  134. try {
  135. this.resultContent = require('html-minifier').minify(html, options);
  136. this.buildCompressInfo(this.sourceContent, this.resultContent);
  137. } catch (err) {
  138. this.hasError = true;
  139. this.resultContent = err;
  140. }
  141. },
  142. toast(content) {
  143. window.clearTimeout(window.feHelperAlertMsgTid);
  144. let elAlertMsg = document.querySelector("#fehelper_alertmsg");
  145. if (!elAlertMsg) {
  146. let elWrapper = document.createElement('div');
  147. elWrapper.innerHTML = '<div id="fehelper_alertmsg">' + content + '</div>';
  148. elAlertMsg = elWrapper.childNodes[0];
  149. document.body.appendChild(elAlertMsg);
  150. } else {
  151. elAlertMsg.innerHTML = content;
  152. elAlertMsg.style.display = 'block';
  153. }
  154. window.feHelperAlertMsgTid = window.setTimeout(function () {
  155. elAlertMsg.style.display = 'none';
  156. }, 3000);
  157. },
  158. copyToClipboard(text) {
  159. if (this.hasError) return false;
  160. let input = document.createElement('textarea');
  161. input.style.position = 'fixed';
  162. input.style.opacity = 0;
  163. input.value = text;
  164. document.body.appendChild(input);
  165. input.select();
  166. document.execCommand('Copy');
  167. document.body.removeChild(input);
  168. this.toast('压缩结果已复制成功,随处粘贴可用!');
  169. },
  170. loadExample(type,event) {
  171. if(event){
  172. event.preventDefault();
  173. }
  174. this.codeType = type;
  175. editor.setValue(EXAMPLES[type]);
  176. this.changeCodeType(type);
  177. },
  178. openOptionsPage: function(event) {
  179. event.preventDefault();
  180. event.stopPropagation();
  181. chrome.runtime.openOptionsPage();
  182. },
  183. openDonateModal: function(event ){
  184. event.preventDefault();
  185. event.stopPropagation();
  186. chrome.runtime.sendMessage({
  187. type: 'fh-dynamic-any-thing',
  188. thing: 'open-donate-modal',
  189. params: { toolName: 'code-compress' }
  190. });
  191. }
  192. }
  193. });