diff --git a/.eslintignore b/.eslintignore index 512bdec8..c0557f7d 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,9 +1,8 @@ # built by tools -client/js/libs.min.js -client/js/lounge.templates.js +client/js/bundle.js +client/js/bundle.vendor.js # third party client/js/libs/jquery/*.js -client/js/libs/*.js coverage/ diff --git a/.eslintrc.yml b/.eslintrc.yml index 1f4469f2..016b18a4 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -44,10 +44,5 @@ rules: globals: log: false - $: false - Favico: false - Handlebars: false - io: false - Mousetrap: false extends: eslint:recommended diff --git a/.gitignore b/.gitignore index 082fcf7b..205dd543 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ coverage/ # Built assets created at npm install/prepublish time # See https://docs.npmjs.com/misc/scripts client/fonts/ -client/js/libs.min.js.map -client/js/libs.min.js -client/js/lounge.templates.js +client/js/bundle.js +client/js/bundle.js.map +client/js/bundle.vendor.js +client/js/bundle.vendor.js.map diff --git a/.istanbul.yml b/.istanbul.yml index e6e79229..f5671bc8 100644 --- a/.istanbul.yml +++ b/.istanbul.yml @@ -1,8 +1,6 @@ instrumentation: include-all-sources: true excludes: - - Gruntfile.js - - client/js/libs/*.js - - client/js/libs/jquery/*.js - - client/js/libs.min.js + - client/js/bundle.js + - client/js/bundle.vendor.js - client/js/lounge.js diff --git a/.npmignore b/.npmignore index 6115c65f..3ae7e661 100644 --- a/.npmignore +++ b/.npmignore @@ -2,6 +2,7 @@ # npm-debug.log and node_modules/ are ignored by default. # See https://docs.npmjs.com/misc/developers#keeping-files-out-of-your-package +client/js/bundle.vendor.js.map client/views/ coverage/ scripts/ @@ -16,4 +17,3 @@ test/ .stylelintrc .travis.yml appveyor.yml -Gruntfile.js diff --git a/client/.eslintrc.yml b/client/.eslintrc.yml new file mode 100644 index 00000000..cb4e55ff --- /dev/null +++ b/client/.eslintrc.yml @@ -0,0 +1,3 @@ +--- +parserOptions: + sourceType: module diff --git a/client/index.html b/client/index.html index 4a0ea14b..de9311d7 100644 --- a/client/index.html +++ b/client/index.html @@ -386,10 +386,8 @@ - - - - + + diff --git a/client/js/libs/handlebars/colorClass.js b/client/js/libs/handlebars/colorClass.js index bd371910..53bfc0d4 100644 --- a/client/js/libs/handlebars/colorClass.js +++ b/client/js/libs/handlebars/colorClass.js @@ -1,13 +1,9 @@ -"use strict"; - -Handlebars.registerHelper( - // Generates a string from "color-1" to "color-32" based on an input string - "colorClass", function(str) { - var hash = 0; - for (var i = 0; i < str.length; i++) { - hash += str.charCodeAt(i); - } - - return "color-" + (1 + hash % 32); +// Generates a string from "color-1" to "color-32" based on an input string +module.exports = function(str) { + var hash = 0; + for (var i = 0; i < str.length; i++) { + hash += str.charCodeAt(i); } -); + + return "color-" + (1 + hash % 32); +}; diff --git a/client/js/libs/handlebars/diff.js b/client/js/libs/handlebars/diff.js index 17f366ab..3b2116bd 100644 --- a/client/js/libs/handlebars/diff.js +++ b/client/js/libs/handlebars/diff.js @@ -1,14 +1,10 @@ -"use strict"; - var diff; -Handlebars.registerHelper( - "diff", function(a, opt) { - if (a !== diff) { - diff = a; - return opt.fn(this); - } - - return opt.inverse(this); +module.exports = function(a, opt) { + if (a !== diff) { + diff = a; + return opt.fn(this); } -); + + return opt.inverse(this); +}; diff --git a/client/js/libs/handlebars/equal.js b/client/js/libs/handlebars/equal.js index 4d8f34ef..1d7a4393 100644 --- a/client/js/libs/handlebars/equal.js +++ b/client/js/libs/handlebars/equal.js @@ -1,13 +1,9 @@ -"use strict"; - -Handlebars.registerHelper( - "equal", function(a, b, opt) { - a = a.toString(); - b = b.toString(); - if (a === b) { - return opt.fn(this); - } - - return opt.inverse(this); +module.exports = function(a, b, opt) { + a = a.toString(); + b = b.toString(); + if (a === b) { + return opt.fn(this); } -); + + return opt.inverse(this); +}; diff --git a/client/js/libs/handlebars/localedate.js b/client/js/libs/handlebars/localedate.js index a933ad06..0f85a5f2 100644 --- a/client/js/libs/handlebars/localedate.js +++ b/client/js/libs/handlebars/localedate.js @@ -1,5 +1,3 @@ -"use strict"; - -Handlebars.registerHelper("localedate", function(time) { +module.exports = function(time) { return new Date(time).toLocaleDateString(); -}); +}; diff --git a/client/js/libs/handlebars/localetime.js b/client/js/libs/handlebars/localetime.js index c8dc097a..5318a022 100644 --- a/client/js/libs/handlebars/localetime.js +++ b/client/js/libs/handlebars/localetime.js @@ -1,5 +1,3 @@ -"use strict"; - -Handlebars.registerHelper("localetime", function(time) { +module.exports = function(time) { return new Date(time).toLocaleString(); -}); +}; diff --git a/client/js/libs/handlebars/modes.js b/client/js/libs/handlebars/modes.js index bf97b033..6416515f 100644 --- a/client/js/libs/handlebars/modes.js +++ b/client/js/libs/handlebars/modes.js @@ -1,16 +1,12 @@ -"use strict"; - -Handlebars.registerHelper( - "modes", function(mode) { - var modes = { - "~": "owner", - "&": "admin", - "!": "admin", - "@": "op", - "%": "half-op", - "+": "voice", - "": "normal" - }; - return modes[mode]; - } -); +module.exports = function(mode) { + var modes = { + "~": "owner", + "&": "admin", + "!": "admin", + "@": "op", + "%": "half-op", + "+": "voice", + "": "normal" + }; + return modes[mode]; +}; diff --git a/client/js/libs/handlebars/parse.js b/client/js/libs/handlebars/parse.js index 71a45820..cd61ff7e 100644 --- a/client/js/libs/handlebars/parse.js +++ b/client/js/libs/handlebars/parse.js @@ -1,17 +1,16 @@ -"use strict"; +import Handlebars from "handlebars/runtime"; +import URI from "urijs"; -Handlebars.registerHelper( - "parse", function(text) { - text = Handlebars.Utils.escapeExpression(text); - text = colors(text); - text = channels(text); - text = uri(text); - return text; - } -); +module.exports = function(text) { + text = Handlebars.Utils.escapeExpression(text); + text = colors(text); + text = channels(text); + text = uri(text); + return text; +}; function uri(text) { - return window.URI.withinString(text, function(url) { + return URI.withinString(text, function(url) { if (url.indexOf("javascript:") === 0) { return url; } diff --git a/client/js/libs/handlebars/roundBadgeNumber.js b/client/js/libs/handlebars/roundBadgeNumber.js index 5982acdd..a7750de0 100644 --- a/client/js/libs/handlebars/roundBadgeNumber.js +++ b/client/js/libs/handlebars/roundBadgeNumber.js @@ -1,11 +1,7 @@ -"use strict"; - -Handlebars.registerHelper( - "roundBadgeNumber", function(count) { - if (count < 1000) { - return count; - } - - return (count / 1000).toFixed(2).slice(0, -1) + "k"; +module.exports = function(count) { + if (count < 1000) { + return count; } -); + + return (count / 1000).toFixed(2).slice(0, -1) + "k"; +}; diff --git a/client/js/libs/handlebars/tojson.js b/client/js/libs/handlebars/tojson.js index 7df32f77..fcd0fde1 100644 --- a/client/js/libs/handlebars/tojson.js +++ b/client/js/libs/handlebars/tojson.js @@ -1,7 +1,3 @@ -"use strict"; - -Handlebars.registerHelper( - "toJSON", function(context) { - return JSON.stringify(context); - } -); +module.exports = function(context) { + return window.JSON.stringify(context); +}; diff --git a/client/js/libs/handlebars/tz.js b/client/js/libs/handlebars/tz.js index 9b46be61..14f05e5e 100644 --- a/client/js/libs/handlebars/tz.js +++ b/client/js/libs/handlebars/tz.js @@ -1,19 +1,15 @@ -"use strict"; +module.exports = function(time) { + time = new Date(time); + var h = time.getHours(); + var m = time.getMinutes(); -Handlebars.registerHelper( - "tz", function(time) { - time = new Date(time); - var h = time.getHours(); - var m = time.getMinutes(); - - if (h < 10) { - h = "0" + h; - } - - if (m < 10) { - m = "0" + m; - } - - return h + ":" + m; + if (h < 10) { + h = "0" + h; } -); + + if (m < 10) { + m = "0" + m; + } + + return h + ":" + m; +}; diff --git a/client/js/libs/handlebars/users.js b/client/js/libs/handlebars/users.js index 977fbf90..e52e7526 100644 --- a/client/js/libs/handlebars/users.js +++ b/client/js/libs/handlebars/users.js @@ -1,7 +1,3 @@ -"use strict"; - -Handlebars.registerHelper( - "users", function(count) { - return count + " " + (count === 1 ? "user" : "users"); - } -); +module.exports = function(count) { + return count + " " + (count === 1 ? "user" : "users"); +}; diff --git a/client/js/libs/jquery/inputhistory.js b/client/js/libs/jquery/inputhistory.js index 0cd118e1..add413db 100644 --- a/client/js/libs/jquery/inputhistory.js +++ b/client/js/libs/jquery/inputhistory.js @@ -1,3 +1,5 @@ +import jQuery from "jquery"; + /*! * inputhistory * https://github.com/erming/inputhistory diff --git a/client/js/libs/jquery/stickyscroll.js b/client/js/libs/jquery/stickyscroll.js index e50b748f..c3500be5 100644 --- a/client/js/libs/jquery/stickyscroll.js +++ b/client/js/libs/jquery/stickyscroll.js @@ -1,3 +1,5 @@ +import jQuery from "jquery"; + (function($) { $.fn.unsticky = function() { return this.trigger("unstick.sticky").unbind(".sticky"); diff --git a/client/js/libs/jquery/tabcomplete.js b/client/js/libs/jquery/tabcomplete.js index de131361..5d04794c 100644 --- a/client/js/libs/jquery/tabcomplete.js +++ b/client/js/libs/jquery/tabcomplete.js @@ -1,3 +1,5 @@ +import jQuery from "jquery"; + /*! * tabcomplete * http://github.com/erming/tabcomplete diff --git a/client/js/libs/slideout.js b/client/js/libs/slideout.js index 330c89b3..ef95f1dd 100644 --- a/client/js/libs/slideout.js +++ b/client/js/libs/slideout.js @@ -1,7 +1,7 @@ /** * Simple slideout menu implementation. */ -function slideoutMenu(viewport, menu) { +export default function slideoutMenu(viewport, menu) { var touchStartPos = null; var touchCurPos = null; var touchStartTime = 0; diff --git a/client/js/loading-slow-alert.js b/client/js/loading-slow-alert.js index dcca1847..9709fd86 100644 --- a/client/js/loading-slow-alert.js +++ b/client/js/loading-slow-alert.js @@ -1,3 +1,4 @@ +/* eslint strict: 0 */ "use strict"; /* diff --git a/client/js/lounge.js b/client/js/lounge.js index d2c208e0..774aeddd 100644 --- a/client/js/lounge.js +++ b/client/js/lounge.js @@ -1,4 +1,18 @@ -"use strict"; +// vendor libraries +import "jquery-ui/ui/widgets/sortable"; +import $ from "jquery"; +import io from "socket.io-client"; +import Mousetrap from "mousetrap"; +import URI from "urijs"; + +// our libraries +import "./libs/jquery/inputhistory"; +import "./libs/jquery/stickyscroll"; +import "./libs/jquery/tabcomplete"; +import helpers_parse from "./libs/handlebars/parse"; +import helpers_roundBadgeNumber from "./libs/handlebars/roundBadgeNumber"; +import slideoutMenu from "./libs/slideout"; +import templates from "../views"; $(function() { var path = window.location.pathname + "socket.io/"; @@ -59,10 +73,6 @@ $(function() { var favicon = $("#favicon"); - function render(name, data) { - return Handlebars.templates[name](data); - } - function setLocalStorageItem(key, value) { try { window.localStorage.setItem(key, value); @@ -73,12 +83,6 @@ $(function() { } } - Handlebars.registerHelper( - "partial", function(id) { - return new Handlebars.SafeString(render(id, this)); - } - ); - [ "connect_error", "connect_failed", @@ -229,12 +233,12 @@ $(function() { var id = data.network; var network = sidebar.find("#network-" + id); network.append( - render("chan", { + templates.chan({ channels: [data.chan] }) ); chat.append( - render("chat", { + templates.chat({ channels: [data.chan] }) ); @@ -284,15 +288,18 @@ $(function() { "ctcp", "channel_list", ].indexOf(type) !== -1) { - data.msg.template = "actions/" + type; template = "msg_action"; } else if (type === "unhandled") { template = "msg_unhandled"; } - var msg = $(render(template, data.msg)); - + var msg = $(templates[template](data.msg)); var text = msg.find(".text"); + + if (template === "msg_action") { + text.html(templates.actions[type](data.msg)); + } + if (text.find("i").size() === 1) { text = text.find("i"); } @@ -334,12 +341,12 @@ $(function() { // TODO: If the message is far off in the history, we still need to append the marker into DOM if (!first.length) { - channel.prepend(render("unread_marker")); + channel.prepend(templates.unread_marker()); } else { - first.before(render("unread_marker")); + first.before(templates.unread_marker()); } } else { - channel.append(render("unread_marker")); + channel.append(templates.unread_marker()); } if (data.type !== "lobby") { @@ -351,11 +358,11 @@ $(function() { // Top-most message in a channel if (!lastDate) { lastDate = msgDate; - msg.before(render("date-marker", {msgDate: msgDate})); + msg.before(templates.date_marker({msgDate: msgDate})); } if (lastDate.toDateString() !== msgDate.toDateString()) { - msg.before(render("date-marker", {msgDate: msgDate})); + msg.before(templates.date_marker({msgDate: msgDate})); } lastDate = msgDate; @@ -383,13 +390,13 @@ $(function() { return (oldSortOrder[a] || Number.MAX_VALUE) - (oldSortOrder[b] || Number.MAX_VALUE); }); - users.html(render("user", data)).data("nicks", nicks); + users.html(templates.user(data)).data("nicks", nicks); } function renderNetworks(data) { sidebar.find(".empty").hide(); sidebar.find(".networks").append( - render("network", { + templates.network({ networks: data.networks }) ); @@ -398,7 +405,7 @@ $(function() { return n.channels; }); chat.append( - render("chat", { + templates.chat({ channels: channels }) ); @@ -424,11 +431,11 @@ $(function() { // It's the first message in a channel/query if (prevMsg.length === 0) { - container.append(render("date-marker", {msgDate: msgTime})); + container.append(templates.date_marker({msgDate: msgTime})); } if (prevMsgTime.toDateString() !== msgTime.toDateString()) { - prevMsg.append(render("date-marker", {msgDate: msgTime})); + prevMsg.append(templates.date_marker({msgDate: msgTime})); } // Add message to the container @@ -486,11 +493,11 @@ $(function() { // Top-most message in a channel if (!lastDate) { lastDate = msgDate; - msg.before(render("date-marker", {msgDate: msgDate})); + msg.before(templates.date_marker({msgDate: msgDate})); } if (lastDate.toDateString() !== msgDate.toDateString()) { - msg.before(render("date-marker", {msgDate: msgDate})); + msg.before(templates.date_marker({msgDate: msgDate})); } lastDate = msgDate; @@ -551,7 +558,7 @@ $(function() { socket.on("toggle", function(data) { var toggle = $("#toggle-" + data.id); - toggle.parent().after(render("toggle", {toggle: data})); + toggle.parent().after(templates.toggle({toggle: data})); switch (data.type) { case "link": if (options.links) { @@ -569,7 +576,7 @@ $(function() { socket.on("topic", function(data) { var topic = $("#chan-" + data.chan).find(".header .topic"); - topic.html(Handlebars.helpers.parse(data.topic)); + topic.html(helpers_parse(data.topic)); // .attr() is safe escape-wise but consider the capabilities of the attribute topic.attr("title", data.topic); }); @@ -710,7 +717,7 @@ $(function() { }()); var viewport = $("#viewport"); - var sidebarSlide = window.slideoutMenu(viewport[0], sidebar[0]); + var sidebarSlide = slideoutMenu(viewport[0], sidebar[0]); var contextMenuContainer = $("#context-menu-container"); var contextMenu = $("#context-menu"); @@ -758,19 +765,19 @@ $(function() { var output = ""; if (target.hasClass("user")) { - output = render("contextmenu_item", { + output = templates.contextmenu_item({ class: "user", text: target.text(), data: target.data("name") }); } else if (target.hasClass("chan")) { - output = render("contextmenu_item", { + output = templates.contextmenu_item({ class: "chan", text: target.data("title"), data: target.data("target") }); - output += render("contextmenu_divider"); - output += render("contextmenu_item", { + output += templates.contextmenu_divider(); + output += templates.contextmenu_item({ class: "close", text: target.hasClass("lobby") ? "Disconnect" : target.hasClass("channel") ? "Leave" : "Close", data: target.data("target") @@ -1178,7 +1185,7 @@ $(function() { return; } - var badge = button.find(".badge").html(Handlebars.helpers.roundBadgeNumber(unread)); + var badge = button.find(".badge").html(helpers_roundBadgeNumber(unread)); if (msg.highlight) { badge.addClass("highlight"); @@ -1226,7 +1233,7 @@ $(function() { }); if ($("body").hasClass("public")) { $("#connect").one("show", function() { - var params = window.URI(document.location.search); + var params = URI(document.location.search); params = params.search(true); // Possible parameters: name, host, port, password, tls, nick, username, realname, join // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in#Iterating_over_own_properties_only diff --git a/client/views/index.js b/client/views/index.js new file mode 100644 index 00000000..2890dea9 --- /dev/null +++ b/client/views/index.js @@ -0,0 +1,30 @@ +module.exports = { + actions: { + action: require("./actions/action.tpl"), + channel_list: require("./actions/channel_list.tpl"), + ctcp: require("./actions/ctcp.tpl"), + invite: require("./actions/invite.tpl"), + join: require("./actions/join.tpl"), + kick: require("./actions/kick.tpl"), + mode: require("./actions/mode.tpl"), + nick: require("./actions/nick.tpl"), + part: require("./actions/part.tpl"), + quit: require("./actions/quit.tpl"), + topic: require("./actions/topic.tpl"), + topic_set_by: require("./actions/topic_set_by.tpl"), + whois: require("./actions/whois.tpl"), + }, + + chan: require("./chan.tpl"), + chat: require("./chat.tpl"), + contextmenu_divider: require("./contextmenu_divider.tpl"), + contextmenu_item: require("./contextmenu_item.tpl"), + date_marker: require("./date-marker.tpl"), + msg: require("./msg.tpl"), + msg_action: require("./msg_action.tpl"), + msg_unhandled: require("./msg_unhandled.tpl"), + network: require("./network.tpl"), + toggle: require("./toggle.tpl"), + unread_marker: require("./unread_marker.tpl"), + user: require("./user.tpl"), +}; diff --git a/client/views/msg.tpl b/client/views/msg.tpl index 1f2be842..72811106 100644 --- a/client/views/msg.tpl +++ b/client/views/msg.tpl @@ -13,7 +13,7 @@ {{#if toggle}} - {{partial "toggle"}} + {{> toggle}} {{/if}} {{else}} diff --git a/client/views/msg_action.tpl b/client/views/msg_action.tpl index 1735fa3f..c2e9657c 100644 --- a/client/views/msg_action.tpl +++ b/client/views/msg_action.tpl @@ -3,7 +3,5 @@ {{tz time}} - - {{partial template}} - + diff --git a/client/views/network.tpl b/client/views/network.tpl index c10162a0..9da98019 100644 --- a/client/views/network.tpl +++ b/client/views/network.tpl @@ -1,5 +1,5 @@ {{#each networks}} -
- {{partial "chan"}} +
+ {{> chan}}
{{/each}} diff --git a/package.json b/package.json index 056859ae..c430d8b8 100644 --- a/package.json +++ b/package.json @@ -14,16 +14,15 @@ "scripts": { "coverage": "istanbul cover node_modules/mocha/bin/_mocha", "start": "node index", + "start-dev": "npm-run-all --parallel watch start", "build": "npm-run-all build:*", "build:font-awesome": "node scripts/build-fontawesome.js", - "build:libs": "uglifyjs client/js/libs/*.js client/js/libs/jquery/*.js client/js/libs/handlebars/*.js -o client/js/libs.min.js --source-map client/js/libs.min.js.map --source-map-url libs.min.js.map -p relative", - "build:handlebars": "handlebars client/views/ -e tpl -f client/js/lounge.templates.js", - "test": "npm-run-all -c test:mocha lint", + "build:webpack": "webpack", + "watch": "webpack -w", + "test": "npm-run-all -c test:* lint", "test:mocha": "mocha", - "lint": "npm-run-all -c lint:js lint:css", - "lint:js": "npm-run-all -c lint:js:es5 lint:js:es6", - "lint:js:es5": "eslint --parser-options=\"ecmaVersion:5\" client/", - "lint:js:es6": "eslint --ignore-pattern client/ .", + "lint": "npm-run-all -c lint:*", + "lint:js": "eslint .", "lint:css": "stylelint \"**/*.css\"", "prepublish": "npm run build" }, @@ -59,14 +58,23 @@ "ldapjs": "1.0.1" }, "devDependencies": { + "babel-core": "6.21.0", + "babel-loader": "6.2.10", + "babel-preset-es2015": "6.18.0", "chai": "3.5.0", "eslint": "3.12.2", "font-awesome": "4.7.0", "handlebars": "4.0.6", + "handlebars-loader": "1.4.0", "istanbul": "0.4.5", + "jquery": "2.1.1", + "jquery-ui": "1.12.1", "mocha": "3.2.0", + "mousetrap": "1.4.6", "npm-run-all": "3.1.2", + "socket.io-client": "1.7.2", "stylelint": "7.7.0", - "uglify-js": "2.7.5" + "urijs": "1.16.1", + "webpack": "1.14.0" } } diff --git a/src/server.js b/src/server.js index 3708c844..700cc7b0 100644 --- a/src/server.js +++ b/src/server.js @@ -64,6 +64,7 @@ module.exports = function() { } var sockets = io(server, { + serveClient: false, transports: config.transports }); diff --git a/test/client/js/libs/handlebars/localetimeTest.js b/test/client/js/libs/handlebars/localetimeTest.js index 66cbc648..75debd8e 100644 --- a/test/client/js/libs/handlebars/localetimeTest.js +++ b/test/client/js/libs/handlebars/localetimeTest.js @@ -1,15 +1,11 @@ "use strict"; -const Handlebars = global.Handlebars = require("handlebars"); const expect = require("chai").expect; - -require("../../../../../client/js/libs/handlebars/localetime"); +const localetime = require("../../../../../client/js/libs/handlebars/localetime"); describe("localetime Handlebars helper", () => { it("should render a human-readable date", () => { - const template = Handlebars.compile("{{localetime time}}"); - // 12PM in UTC time const date = new Date("2014-05-22T12:00:00"); @@ -19,7 +15,7 @@ describe("localetime Handlebars helper", () => { // Pretend local timezone is UTC by moving the clock of that offset const time = date.getTime() + offset; - expect(template({time: time})).to.equal("5/22/2014, 12:00:00 PM"); + expect(localetime(time)).to.equal("5/22/2014, 12:00:00 PM"); }); }); diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..a09897ce --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,66 @@ +"use strict"; + +const webpack = require("webpack"); +const path = require("path"); + +module.exports = { + entry: { + app: path.resolve(__dirname, "client/js/lounge.js"), + vendor: [ + "handlebars/runtime", + "jquery", + "jquery-ui/ui/widgets/sortable", + "mousetrap", + "socket.io-client", + "urijs", + ], + }, + devtool: "source-map", + output: { + path: path.resolve(__dirname, "client/js"), + filename: "bundle.js", + publicPath: "/" + }, + module: { + loaders: [ + { + test: /\.js$/, + include: [ + path.resolve(__dirname, "client"), + ], + loader: "babel", + query: { + presets: [ + "es2015" + ] + } + }, + { + test: /\.tpl$/, + include: [ + path.resolve(__dirname, "client/views"), + ], + loader: "handlebars-loader", + query: { + helperDirs: [ + path.resolve(__dirname, "client/js/libs/handlebars") + ], + extensions: [ + ".tpl" + ], + } + }, + ] + }, + plugins: [ + new webpack.optimize.CommonsChunkPlugin( + "vendor", // chunkName + "bundle.vendor.js" // filename + ), + new webpack.optimize.UglifyJsPlugin({ + compress: { + warnings: false + } + }), + ] +};