之前发布的一个JFinal的css,js压缩的Combo Handler:http://www.dreamlu.net/blog/17
该Handler可按照指定规则压缩并合并js和css,比较常见!淘宝,窝窝团都是采用的类似的方式!之前我也是参看窝窝团研发副总裁的博客才写了这样一个插件!
在强大的BAE2.0的cdn下,不得不承认该Handler还是有一定的效果!在迁移到3.0时,想使用七牛的镜像来做cdn!由于七牛云镜像不支持URL参数,发现之前的Combo Handler完全失效了!被迫开启了2.0的cnd依然使用2.0的来实现加速!
昨天在github查看express-coffee源码的时候发现了connect-assets插件,这是一个实现类似rails中的asset框架!connect-assets中的源码采用coffee编写,这个我再喜欢不过了!大致的看了下,他是使用的一个模版标签去生成css,js的链接的,我恍然大悟!
于是,我也采用类似的方法,写了个combo的Jade的模版标签!
由于我的博分得有前台和后台不能像那些rails一样将所有的js,css压成一个(感觉这样比较浪费),于是多加了一个参数‘assets-web.jcss’,它用来记录这需要合并的js或者css,我对其分别以jcss和jjs的后缀区分!
用@标记需要合并压缩的css或者js,加一个版本信息是为了更改之后方便重新生成合并压缩后的文件(没有采用对整个需要合并压缩的文件哈希的方式,看官可自行完善)!
上面是ruby-china的js链接!
下面是本博Jade模版的标签生成的css链接!这样做的最大好处就是节省请求时间,在第一次请求发现木有此css时则自动根绝规则文件去生成这个css,如果存在,则直接返回路径!如果规则文件被修改该文件的hex值发生改变,也同样会去生成新的css文件!
最核心的代码:AssetsKit.java (有问题可以骚扰我,欢迎点击osc地址留言!)
private static final Logger log = Logger.getLogger(AssetsKit.class);\r\n public static final String CHARSET = "UTF-8";\r\n public static final String JS_EXT = ".js", CSS_EXT = ".css";\r\n\r\n /**\r\n * 压缩css,js\r\n * @param queryString\r\n * @param isCss\r\n * @param out\r\n * @return\r\n */\r\n public static boolean compressorHelper(List fileList, boolean isCss, Writer out) {\r\n Reader in = null;\r\n try {\r\n if (isCss) {\r\n for (String path : fileList) {\r\n in = new InputStreamReader(new FileInputStream(path), CHARSET);\r\n if(path.indexOf(".min.") > 0){// 对.min.css的css放弃压缩\r\n out.append(IOKit.readerToString(in));\r\n }else{\r\n CssCompressor css = new CssCompressor(in);\r\n in.close(); in = null;\r\n css.compress(out, -1);\r\n }\r\n }\r\n }else{\r\n // nomunge: 混淆,verbose:显示信息消息和警告,preserveAllSemiColons:保留所有的分号 ,disableOptimizations 禁止优化\r\n boolean munge = true, verbose = false, preserveAllSemiColons = false, disableOptimizations = false;\r\n for (String path : fileList) {\r\n in = new InputStreamReader(new FileInputStream(path), CHARSET);\r\n if(path.indexOf(".min.") > 0){ // 对.min.js的js放弃压缩\r\n out.append(IOKit.readerToString(in));\r\n }else{\r\n JavaScriptCompressor compressor = new JavaScriptCompressor(in, new ErrorReporter() {\r\n public void warning(String message, String sourceName,\r\n int line, String lineSource, int lineOffset) {\r\n if (line < 0) {\r\n log.error("\\n[WARNING] " + message);\r\n } else {\r\n log.error("\\n[WARNING] " + line + ':' + lineOffset + ':' + message);\r\n }\r\n }\r\n public void error(String message, String sourceName,\r\n int line, String lineSource, int lineOffset) {\r\n if (line < 0) {\r\n log.error("\\n[ERROR] " + message);\r\n } else {\r\n log.error("\\n[ERROR] " + line + ':' + lineOffset + ':' + message);\r\n }\r\n }\r\n public EvaluatorException runtimeError(String message, String sourceName,\r\n int line, String lineSource, int lineOffset) {\r\n error(message, sourceName, line, lineSource, lineOffset);\r\n return new EvaluatorException(message);\r\n }\r\n });\r\n in.close(); in = null;\r\n compressor.compress(out, -1, munge, verbose, preserveAllSemiColons, disableOptimizations);\r\n }\r\n }\r\n }\r\n out.flush();\r\n return true;\r\n }catch(IOException e){\r\n e.printStackTrace();\r\n log.error(e);\r\n return false;\r\n }finally{\r\n IOUtils.closeQuietly(in);\r\n IOUtils.closeQuietly(out);\r\n }\r\n }\r\n \r\n @SuppressWarnings("unchecked")\r\n public static String combo(String fileName) {\r\n// String fileName = "/assets/assets-web.jcss";\r\n// String fileName = "/assets/assets-web.jjs";\r\n String rootPath = PathKit.getWebRootPath();\r\n String comboName = fileName.substring(0, fileName.indexOf(".")); // /assets/assets-web\r\n \r\n Writer out = null;\r\n try {\r\n // 读取文件中的js或者css路径\r\n List list = FileUtils.readLines(new File(rootPath + fileName), CHARSET);\r\n List comboList = Lists.newArrayList(); // 文件路基\r\n StringBuilder sb = new StringBuilder(); // 文件内容\r\n for (String string : list) {\r\n if (string.startsWith("@")) {\r\n comboList.add(PathKit.getWebRootPath() + string.substring(1, string.length()));\r\n }\r\n sb.append(string);\r\n }\r\n // 文件内容hex\r\n String hex = DigestUtils.md5Hex(sb.toString()); // 为了方便没有md5整个文件集\r\n \r\n boolean isCss = true;\r\n if (fileName.endsWith(".jjs")) {\r\n isCss = false;\r\n }\r\n \r\n String newFileName = comboName + "-" + hex + (isCss ? CSS_EXT : JS_EXT);\r\n \r\n String newPath = rootPath + newFileName;\r\n File file = new File(newPath);\r\n \r\n boolean temp = file.exists();\r\n if (temp) {\r\n return newFileName;\r\n }\r\n \r\n out = new OutputStreamWriter(new FileOutputStream(newPath), CHARSET);\r\n compressorHelper(comboList, isCss, out);\r\n \r\n return newFileName;\r\n } catch (UnsupportedEncodingException e) {\r\n e.printStackTrace();\r\n } catch (FileNotFoundException e) {\r\n e.printStackTrace();\r\n } catch (IOException e) {\r\n e.printStackTrace();\r\n }finally{\r\n IOUtils.closeQuietly(out);\r\n }\r\n return null;\r\n }
联系客服