css-builder.js 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. define(['require', './normalize'], function(req, normalize) {
  2. var cssAPI = {};
  3. var isWindows = !!process.platform.match(/^win/);
  4. function compress(css) {
  5. if (config.optimizeCss == 'none') {
  6. return css;
  7. }
  8. if (typeof process !== "undefined" && process.versions && !!process.versions.node && require.nodeRequire) {
  9. try {
  10. var csso = require.nodeRequire('csso');
  11. }
  12. catch(e) {
  13. console.log('Compression module not installed. Use "npm install csso -g" to enable.');
  14. return css;
  15. }
  16. var csslen = css.length;
  17. try {
  18. if (typeof csso.minify === 'function') {
  19. var minifyResult = csso.minify(css);
  20. if (typeof minifyResult === 'string'){ // for csso < 2.0.0
  21. css = minifyResult;
  22. } else if (typeof minifyResult === 'object'){ // for csso >= 2.0.0
  23. css = minifyResult.css;
  24. }
  25. } else { // justDoIt() was always. minify() appeared in csso 1.4.0.
  26. css = csso.justDoIt(css);
  27. }
  28. }
  29. catch(e) {
  30. console.log('Compression failed due to a CSS syntax error.');
  31. return css;
  32. }
  33. console.log('Compressed CSS output to ' + Math.round(css.length / csslen * 100) + '%.');
  34. return css;
  35. }
  36. console.log('Compression not supported outside of nodejs environments.');
  37. return css;
  38. }
  39. //load file code - stolen from text plugin
  40. function loadFile(path) {
  41. if (typeof process !== "undefined" && process.versions && !!process.versions.node && require.nodeRequire) {
  42. var fs = require.nodeRequire('fs');
  43. var file = fs.readFileSync(path, 'utf8');
  44. if (file.indexOf('\uFEFF') === 0)
  45. return file.substring(1);
  46. return file;
  47. }
  48. else {
  49. var file = new java.io.File(path),
  50. lineSeparator = java.lang.System.getProperty("line.separator"),
  51. input = new java.io.BufferedReader(new java.io.InputStreamReader(new java.io.FileInputStream(file), 'utf-8')),
  52. stringBuffer, line;
  53. try {
  54. stringBuffer = new java.lang.StringBuffer();
  55. line = input.readLine();
  56. if (line && line.length() && line.charAt(0) === 0xfeff)
  57. line = line.substring(1);
  58. stringBuffer.append(line);
  59. while ((line = input.readLine()) !== null) {
  60. stringBuffer.append(lineSeparator).append(line);
  61. }
  62. return String(stringBuffer.toString());
  63. }
  64. finally {
  65. input.close();
  66. }
  67. }
  68. }
  69. function saveFile(path, data) {
  70. if (typeof process !== "undefined" && process.versions && !!process.versions.node && require.nodeRequire) {
  71. var fs = require.nodeRequire('fs');
  72. fs.writeFileSync(path, data, 'utf8');
  73. }
  74. else {
  75. var content = new java.lang.String(data);
  76. var output = new java.io.BufferedWriter(new java.io.OutputStreamWriter(new java.io.FileOutputStream(path), 'utf-8'));
  77. try {
  78. output.write(content, 0, content.length());
  79. output.flush();
  80. }
  81. finally {
  82. output.close();
  83. }
  84. }
  85. }
  86. //when adding to the link buffer, paths are normalised to the baseUrl
  87. //when removing from the link buffer, paths are normalised to the output file path
  88. function escape(content) {
  89. return content.replace(/(["'\\])/g, '\\$1')
  90. .replace(/[\f]/g, "\\f")
  91. .replace(/[\b]/g, "\\b")
  92. .replace(/[\n]/g, "\\n")
  93. .replace(/[\t]/g, "\\t")
  94. .replace(/[\r]/g, "\\r");
  95. }
  96. // NB add @media query support for media imports
  97. var importRegEx = /@import\s*(url)?\s*(('([^']*)'|"([^"]*)")|\(('([^']*)'|"([^"]*)"|([^\)]*))\))\s*;?/g;
  98. var absUrlRegEx = /^([^\:\/]+:\/)?\//;
  99. // Write Css module definition
  100. var writeCSSDefinition = "define('@writecss', function() {return function writeCss(c) {var d=document,a='appendChild',i='styleSheet',s=d.createElement('style');s.type='text/css';d.getElementsByTagName('head')[0][a](s);s[i]?s[i].cssText=c:s[a](d.createTextNode(c));};});";
  101. var siteRoot;
  102. var baseParts = req.toUrl('base_url').split('/');
  103. baseParts[baseParts.length - 1] = '';
  104. var baseUrl = baseParts.join('/');
  105. var curModule = 0;
  106. var config;
  107. var writeCSSForLayer = true;
  108. var layerBuffer = [];
  109. var cssBuffer = {};
  110. cssAPI.load = function(name, req, load, _config) {
  111. //store config
  112. config = config || _config;
  113. if (!siteRoot) {
  114. siteRoot = path.resolve(config.dir || path.dirname(config.out), config.siteRoot || '.') + '/';
  115. if (isWindows)
  116. siteRoot = siteRoot.replace(/\\/g, '/');
  117. }
  118. //external URLS don't get added (just like JS requires)
  119. if (name.match(absUrlRegEx))
  120. return load();
  121. var fileUrl = req.toUrl(name + '.css');
  122. if (isWindows)
  123. fileUrl = fileUrl.replace(/\\/g, '/');
  124. // rebase to the output directory if based on the source directory;
  125. // baseUrl points always to the output directory, fileUrl only if
  126. // it is not prefixed by a computed path (relative too)
  127. var fileSiteUrl = fileUrl;
  128. if (fileSiteUrl.indexOf(baseUrl) < 0) {
  129. var appRoot = req.toUrl(config.appDir);
  130. if (isWindows)
  131. appRoot = appRoot.replace(/\\/g, '/');
  132. if (fileSiteUrl.indexOf(appRoot) == 0)
  133. fileSiteUrl = siteRoot + fileSiteUrl.substring(appRoot.length);
  134. }
  135. //add to the buffer
  136. cssBuffer[name] = normalize(loadFile(fileUrl), fileSiteUrl, siteRoot);
  137. load();
  138. }
  139. cssAPI.normalize = function(name, normalize) {
  140. if (name.substr(name.length - 4, 4) == '.css')
  141. name = name.substr(0, name.length - 4);
  142. return normalize(name);
  143. }
  144. cssAPI.write = function(pluginName, moduleName, write, parse) {
  145. var cssModule;
  146. //external URLS don't get added (just like JS requires)
  147. if (moduleName.match(absUrlRegEx))
  148. return;
  149. layerBuffer.push(cssBuffer[moduleName]);
  150. if (!global._requirejsCssData) {
  151. global._requirejsCssData = {
  152. usedBy: {css: true},
  153. css: ''
  154. }
  155. } else {
  156. global._requirejsCssData.usedBy.css = true;
  157. }
  158. if (config.buildCSS != false) {
  159. var style = cssBuffer[moduleName];
  160. if (config.writeCSSModule && style) {
  161. if (writeCSSForLayer) {
  162. writeCSSForLayer = false;
  163. write(writeCSSDefinition);
  164. }
  165. cssModule = 'define(["@writecss"], function(writeCss){\n writeCss("'+ escape(compress(style)) +'");\n})';
  166. }
  167. else {
  168. cssModule = 'define(function(){})';
  169. }
  170. write.asModule(pluginName + '!' + moduleName, cssModule);
  171. }
  172. }
  173. cssAPI.onLayerEnd = function(write, data) {
  174. if (config.separateCSS && config.IESelectorLimit)
  175. throw 'RequireCSS: separateCSS option is not compatible with ensuring the IE selector limit';
  176. if (config.separateCSS) {
  177. var outPath = data.path.replace(/(\.js)?$/, '.css');
  178. console.log('Writing CSS! file: ' + outPath + '\n');
  179. var css = layerBuffer.join('');
  180. process.nextTick(function() {
  181. if (global._requirejsCssData) {
  182. css = global._requirejsCssData.css = css + global._requirejsCssData.css;
  183. delete global._requirejsCssData.usedBy.css;
  184. if (Object.keys(global._requirejsCssData.usedBy).length === 0) {
  185. delete global._requirejsCssData;
  186. }
  187. }
  188. saveFile(outPath, compress(css));
  189. });
  190. }
  191. else if (config.buildCSS != false && config.writeCSSModule != true) {
  192. var styles = config.IESelectorLimit ? layerBuffer : [layerBuffer.join('')];
  193. for (var i = 0; i < styles.length; i++) {
  194. if (styles[i] == '')
  195. return;
  196. write(
  197. "(function(c){var d=document,a='appendChild',i='styleSheet',s=d.createElement('style');s.type='text/css';d.getElementsByTagName('head')[0][a](s);s[i]?s[i].cssText=c:s[a](d.createTextNode(c));})\n"
  198. + "('" + escape(compress(styles[i])) + "');\n"
  199. );
  200. }
  201. }
  202. //clear layer buffer for next layer
  203. layerBuffer = [];
  204. writeCSSForLayer = true;
  205. }
  206. return cssAPI;
  207. });