Gruntfile.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. const webpack = require("webpack");
  2. const ExtractTextPlugin = require("extract-text-webpack-plugin");
  3. const HtmlWebpackPlugin = require("html-webpack-plugin");
  4. const Inliner = require("web-resource-inliner");
  5. module.exports = function (grunt) {
  6. grunt.file.defaultEncoding = "utf8";
  7. grunt.file.preserveBOM = false;
  8. // Tasks
  9. grunt.registerTask("dev",
  10. "A persistent task which creates a development build whenever source files are modified.",
  11. ["clean:dev", "webpack:webDev"]);
  12. grunt.registerTask("node",
  13. "Compiles CyberChef into a single NodeJS module.",
  14. ["clean:node", "webpack:node", "chmod:build"]);
  15. grunt.registerTask("test",
  16. "A task which runs all the tests in test/tests.",
  17. ["clean:test", "webpack:tests", "execute:test"]);
  18. grunt.registerTask("docs",
  19. "Compiles documentation in the /docs directory.",
  20. ["clean:docs", "jsdoc", "chmod:docs"]);
  21. grunt.registerTask("prod",
  22. "Creates a production-ready build. Use the --msg flag to add a compile message.",
  23. ["eslint", "clean:prod", "webpack:webProd", "inline", "chmod"]);
  24. grunt.registerTask("default",
  25. "Lints the code base",
  26. ["eslint", "exec:repoSize"]);
  27. grunt.registerTask("inline",
  28. "Compiles a production build of CyberChef into a single, portable web page.",
  29. runInliner);
  30. grunt.registerTask("doc", "docs");
  31. grunt.registerTask("tests", "test");
  32. grunt.registerTask("lint", "eslint");
  33. // Load tasks provided by each plugin
  34. grunt.loadNpmTasks("grunt-eslint");
  35. grunt.loadNpmTasks("grunt-webpack");
  36. grunt.loadNpmTasks("grunt-jsdoc");
  37. grunt.loadNpmTasks("grunt-contrib-clean");
  38. grunt.loadNpmTasks("grunt-contrib-copy");
  39. grunt.loadNpmTasks("grunt-chmod");
  40. grunt.loadNpmTasks("grunt-exec");
  41. grunt.loadNpmTasks("grunt-execute");
  42. grunt.loadNpmTasks("grunt-accessibility");
  43. // Project configuration
  44. const compileTime = grunt.template.today("dd/mm/yyyy HH:MM:ss") + " UTC",
  45. banner = "/**\n" +
  46. "* CyberChef - The Cyber Swiss Army Knife\n" +
  47. "*\n" +
  48. "* @copyright Crown Copyright 2016\n" +
  49. "* @license Apache-2.0\n" +
  50. "*\n" +
  51. "* Copyright 2016 Crown Copyright\n" +
  52. "*\n" +
  53. '* Licensed under the Apache License, Version 2.0 (the "License");\n' +
  54. "* you may not use this file except in compliance with the License.\n" +
  55. "* You may obtain a copy of the License at\n" +
  56. "*\n" +
  57. "* http://www.apache.org/licenses/LICENSE-2.0\n" +
  58. "*\n" +
  59. "* Unless required by applicable law or agreed to in writing, software\n" +
  60. '* distributed under the License is distributed on an "AS IS" BASIS,\n' +
  61. "* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n" +
  62. "* See the License for the specific language governing permissions and\n" +
  63. "* limitations under the License.\n" +
  64. "*/\n";
  65. /**
  66. * Compiles a production build of CyberChef into a single, portable web page.
  67. */
  68. function runInliner() {
  69. const done = this.async();
  70. Inliner.html({
  71. relativeTo: "build/prod/",
  72. fileContent: grunt.file.read("build/prod/cyberchef.htm"),
  73. images: true,
  74. svgs: true,
  75. scripts: true,
  76. links: true,
  77. strict: true
  78. }, function(error, result) {
  79. if (error) {
  80. if (error instanceof Error) {
  81. done(error);
  82. } else {
  83. done(new Error(error));
  84. }
  85. } else {
  86. grunt.file.write("build/prod/cyberchef.htm", result);
  87. done(true);
  88. }
  89. });
  90. }
  91. grunt.initConfig({
  92. clean: {
  93. dev: ["build/dev/*"],
  94. prod: ["build/prod/*"],
  95. test: ["build/test/*"],
  96. node: ["build/node/*"],
  97. docs: ["docs/*", "!docs/*.conf.json", "!docs/*.ico"],
  98. },
  99. eslint: {
  100. options: {
  101. configFile: "./.eslintrc.json"
  102. },
  103. configs: ["Gruntfile.js"],
  104. core: ["src/core/**/*.js", "!src/core/lib/**/*"],
  105. web: ["src/web/**/*.js"],
  106. node: ["src/node/**/*.js"],
  107. tests: ["test/**/*.js"],
  108. },
  109. jsdoc: {
  110. options: {
  111. destination: "docs",
  112. template: "node_modules/ink-docstrap/template",
  113. recurse: true,
  114. readme: "./README.md",
  115. configure: "docs/jsdoc.conf.json"
  116. },
  117. all: {
  118. src: [
  119. "src/**/*.js",
  120. "!src/core/lib/**/*",
  121. ],
  122. }
  123. },
  124. accessibility: {
  125. options: {
  126. accessibilityLevel: "WCAG2A",
  127. verbose: false,
  128. ignore: [
  129. "WCAG2A.Principle1.Guideline1_3.1_3_1.H42.2"
  130. ]
  131. },
  132. test: {
  133. src: ["build/**/*.html"]
  134. }
  135. },
  136. webpack: {
  137. options: {
  138. plugins: [
  139. new webpack.ProvidePlugin({
  140. $: "jquery",
  141. jQuery: "jquery",
  142. moment: "moment-timezone"
  143. }),
  144. new webpack.BannerPlugin({
  145. banner: banner,
  146. raw: true,
  147. entryOnly: true
  148. }),
  149. new webpack.DefinePlugin({
  150. COMPILE_TIME: JSON.stringify(compileTime),
  151. COMPILE_MSG: JSON.stringify(grunt.option("compile-msg") || grunt.option("msg") || "")
  152. }),
  153. new ExtractTextPlugin("styles.css"),
  154. ],
  155. resolve: {
  156. alias: {
  157. jquery: "jquery/src/jquery"
  158. }
  159. },
  160. module: {
  161. rules: [
  162. {
  163. test: /\.js$/,
  164. exclude: /node_modules/,
  165. loader: "babel-loader?compact=false"
  166. },
  167. {
  168. test: /\.css$/,
  169. use: ExtractTextPlugin.extract({
  170. use: "css-loader?minimize"
  171. })
  172. },
  173. {
  174. test: /\.less$/,
  175. use: ExtractTextPlugin.extract({
  176. use: [
  177. { loader: "css-loader?minimize" },
  178. { loader: "less-loader" }
  179. ]
  180. })
  181. },
  182. {
  183. test: /\.(ico|eot|ttf|woff|woff2)$/,
  184. loader: "url-loader",
  185. options: {
  186. limit: 10000
  187. }
  188. },
  189. { // First party images are saved as files to be cached
  190. test: /\.(png|jpg|gif|svg)$/,
  191. exclude: /node_modules/,
  192. loader: "file-loader",
  193. options: {
  194. name: "images/[name].[ext]"
  195. }
  196. },
  197. { // Third party images are inlined
  198. test: /\.(png|jpg|gif|svg)$/,
  199. exclude: /web\/static/,
  200. loader: "url-loader",
  201. options: {
  202. limit: 10000
  203. }
  204. },
  205. ]
  206. },
  207. stats: {
  208. children: false,
  209. warningsFilter: /source-map/
  210. }
  211. },
  212. webDev: {
  213. target: "web",
  214. entry: "./src/web/index.js",
  215. output: {
  216. filename: "scripts.js",
  217. path: __dirname + "/build/dev"
  218. },
  219. plugins: [
  220. new HtmlWebpackPlugin({
  221. filename: "index.html",
  222. template: "./src/web/html/index.html",
  223. compileTime: compileTime
  224. })
  225. ],
  226. watch: true
  227. },
  228. webProd: {
  229. target: "web",
  230. entry: "./src/web/index.js",
  231. output: {
  232. filename: "scripts.js",
  233. path: __dirname + "/build/prod"
  234. },
  235. plugins: [
  236. new webpack.optimize.UglifyJsPlugin({
  237. compress: {
  238. "screw_ie8": true,
  239. "dead_code": true,
  240. "unused": true,
  241. "warnings": false
  242. },
  243. comments: false,
  244. }),
  245. new HtmlWebpackPlugin({ // Main version
  246. filename: "index.html",
  247. template: "./src/web/html/index.html",
  248. compileTime: compileTime,
  249. minify: {
  250. removeComments: true,
  251. collapseWhitespace: true,
  252. minifyJS: true,
  253. minifyCSS: true
  254. }
  255. }),
  256. new HtmlWebpackPlugin({ // Inline version
  257. filename: "cyberchef.htm",
  258. template: "./src/web/html/index.html",
  259. compileTime: compileTime,
  260. inline: true,
  261. minify: {
  262. removeComments: true,
  263. collapseWhitespace: true,
  264. minifyJS: true,
  265. minifyCSS: true
  266. }
  267. }),
  268. ]
  269. },
  270. tests: {
  271. target: "node",
  272. entry: "./test/index.js",
  273. output: {
  274. filename: "index.js",
  275. path: __dirname + "/build/test"
  276. }
  277. },
  278. node: {
  279. target: "node",
  280. entry: "./src/node/index.js",
  281. output: {
  282. filename: "CyberChef.js",
  283. path: __dirname + "/build/node",
  284. library: "CyberChef",
  285. libraryTarget: "commonjs2"
  286. }
  287. }
  288. },
  289. copy: {
  290. ghPages: {
  291. options: {
  292. process: function (content) {
  293. // Add Google Analytics code to index.html
  294. content = content.replace("</body></html>",
  295. grunt.file.read("src/web/static/ga.html") + "</body></html>");
  296. return grunt.template.process(content);
  297. }
  298. },
  299. src: "build/prod/index.html",
  300. dest: "build/prod/index.html"
  301. }
  302. },
  303. chmod: {
  304. build: {
  305. options: {
  306. mode: "755",
  307. },
  308. src: ["build/**/*", "build/"]
  309. },
  310. docs: {
  311. options: {
  312. mode: "755",
  313. },
  314. src: ["docs/**/*", "docs/"]
  315. }
  316. },
  317. exec: {
  318. repoSize: {
  319. command: [
  320. "git ls-files | wc -l | xargs printf '\n%b\ttracked files\n'",
  321. "du -hs | egrep -o '^[^\t]*' | xargs printf '%b\trepository size\n'"
  322. ].join(";"),
  323. stderr: false
  324. },
  325. cleanGit: {
  326. command: "git gc --prune=now --aggressive"
  327. },
  328. },
  329. execute: {
  330. test: "build/test/index.js"
  331. },
  332. });
  333. };