diff --git a/Gruntfile.js b/Gruntfile.js index 1eb694676..572823b73 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -18,8 +18,6 @@ /*jslint node: true */ "use strict"; -const path = require('path'); - module.exports = function (grunt) { var helper = require('./tasks/helper.js'), initHelper = helper.init(grunt), @@ -195,33 +193,7 @@ module.exports = function (grunt) { template: 'test/nightwatch_tests/nightwatch.json.underscore', dest: 'test/nightwatch_tests/nightwatch.json' } - }, - - // these rename the already-bundled, minified requireJS and CSS files to include their hash - md5: { - bundlejs: { - files: { 'dist/release/dashboard.assets/js/': 'dist/release/bundle.js' }, - options: { - afterEach: function (fileChanges) { - // replace the REQUIREJS_FILE placeholder with the actual filename - const newFilename = path.basename(fileChanges.newPath); - config.template.release.variables.bundlejs = config.template.release.variables.bundlejs.replace(/BUNDLEJS_FILE/, newFilename); - } - } - }, - - css: { - files: { 'dist/release/dashboard.assets/css/': 'dist/release/styles.css' }, - options: { - afterEach: function (fileChanges) { - // replace the CSS_FILE placeholder with the actual filename - const newFilename = path.basename(fileChanges.newPath); - config.template.release.variables.css = config.template.release.variables.css.replace(/CSS_FILE/, newFilename); - } - } - } - }, - + } }; grunt.initConfig(config); @@ -237,7 +209,6 @@ module.exports = function (grunt) { grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-shell'); - grunt.loadNpmTasks('grunt-md5'); /* * Default task */ @@ -255,8 +226,7 @@ module.exports = function (grunt) { grunt.registerTask('dependencies', ['get_deps', 'gen_load_addons:default']); // minify code and css, ready for release. - grunt.registerTask('build', ['copy:distDepsRequire', 'shell:webpackrelease', - 'md5:bundlejs', 'md5:css', 'template:release']); + grunt.registerTask('build', ['copy:distDepsRequire', 'shell:webpackrelease']); /* * Build the app in either dev, debug, or release mode */ @@ -267,13 +237,13 @@ module.exports = function (grunt) { // build a debug release grunt.registerTask('debug', ['clean', 'dependencies', "gen_initialize:development", - 'template:development', 'copy:debug']); + 'copy:debug']); grunt.registerTask('debugDev', ['clean', 'dependencies', "gen_initialize:development", - 'template:development', 'copy:debug', 'shell:webpack']); + 'copy:debug', 'shell:webpack']); grunt.registerTask('devSetup', ['dependencies', "gen_initialize:development", - 'template:development', 'copy:debug']); + 'copy:debug']); grunt.registerTask('devSetupWithClean', ['clean', 'devSetup']); grunt.registerTask('watchRun', ['clean:watch', 'dependencies', 'shell:stylecheck']); diff --git a/assets/index.underscore b/assets/index.underscore index 2d97e0bf4..d92c6e2fa 100644 --- a/assets/index.underscore +++ b/assets/index.underscore @@ -19,11 +19,8 @@ - Project Fauxton + <%= htmlWebpackPlugin.options.title %> - <% if (!development) { %> - - <% } %> - <% if (base) { %> - - <% } %> @@ -53,9 +47,6 @@
- - - - + diff --git a/devserver.js b/devserver.js index c8d0ffc10..dd8f32872 100644 --- a/devserver.js +++ b/devserver.js @@ -1,13 +1,14 @@ -var spawn = require('child_process').spawn; -var fs = require("fs"); -var webpack = require('webpack'); -var WebpackDev = require('webpack-dev-server'); -var config = require('./webpack.config.dev.js'); -var httpProxy = require('http-proxy'); +const spawn = require('child_process').spawn; +const fs = require("fs"); +const webpack = require('webpack'); +const WebpackDev = require('webpack-dev-server'); +const config = require('./webpack.config.dev.js'); +const httpProxy = require('http-proxy'); +const path = require('path'); -var loadSettings = function () { - var fileName = './settings.json.default.json'; +const loadSettings = function () { + let fileName = './settings.json.default.json'; if (fs.existsSync('./settings.json')) { fileName = './settings.json'; } @@ -22,16 +23,16 @@ var loadSettings = function () { }; }; -var settings = loadSettings(); +const settings = loadSettings(); -var devSetup = function (cb) { +const devSetup = function (cb) { console.log('setup dev environment'); - var cmd = 'devSetupWithClean'; + const cmd = 'devSetupWithClean'; if (settings.noClean) { cmd = 'devSetup'; } - var grunt = spawn('grunt', [cmd]); + const grunt = spawn('grunt', [cmd]); grunt.stdout.on('data', (data) => { console.log(data.toString()); @@ -63,26 +64,8 @@ function getCspHeaders () { }; }; -var runWebpackServer = function () { - var options = { - contentBase: __dirname + '/dist/debug', - publicPath: '/', - outputPath: '/', - filename: 'bundle.js', - host: 'localhost', - port: process.env.FAUXTON_PORT || 8000, - hot: false, - historyApiFallback: true, - stats: { - colors: true, - }, - headers: getCspHeaders(), - }; - - var compiler = webpack(config); - - var server = new WebpackDev(compiler, options); - var proxy = httpProxy.createServer({ +const runWebpackServer = function () { + const proxy = httpProxy.createServer({ secure: false, changeOrigin: true, target: settings.proxy.target @@ -98,9 +81,33 @@ var runWebpackServer = function () { // don't explode on cancelled requests }); - server.app.all('*', function (req, res) { - proxy.web(req, res); - }); + const options = { + contentBase: path.join(__dirname, '/dist/debug/'), + host: 'localhost', + port: process.env.FAUXTON_PORT || 8000, + overlay: true, + hot: false, + historyApiFallback: false, + stats: { + colors: true, + }, + headers: getCspHeaders(), + setup: (app) => { + app.all('*', (req, res, next) => { + const accept = req.headers.accept ? req.headers.accept.split(',') : ''; + + if (/application\/json/.test(accept[0])) { + proxy.web(req, res); + return; + } + + next(); + }); + } + }; + + const compiler = webpack(config); + const server = new WebpackDev(compiler, options); server.listen(options.port, '0.0.0.0', function (err) { if (err) { diff --git a/docker/dc.selenium.yml b/docker/dc.selenium.yml index 5d1c3855b..f65f28409 100644 --- a/docker/dc.selenium.yml +++ b/docker/dc.selenium.yml @@ -8,7 +8,7 @@ services: couchdb: container_name: couchdb - image: klaemo/couchdb:2.0-dev@sha256:e9b71abaff6aeaa34ee28604c3aeb78f3a7c789ad74a7b88148e2ef78f1e3b21 + image: klaemo/couchdb:2.0-dev command: '--with-haproxy -a tester:testerpass' ports: - "5984:5984" \ No newline at end of file diff --git a/package.json b/package.json index dabe4dd61..ff101cfbc 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,7 @@ "bootstrap": "^3.3.7", "enzyme": "^2.7.1", "es5-shim": "4.5.4", - "extract-text-webpack-plugin": "^1.0.1", + "extract-text-webpack-plugin": "~2.1.0", "fetch-mock": "^5.9.3", "jest": "^18.1.0", "less": "^2.7.2", @@ -74,8 +74,8 @@ "grunt-contrib-copy": "~1.0.0", "grunt-couchapp": "~0.2.1", "grunt-exec": "~1.0.1", - "grunt-md5": "^0.1.11", "grunt-shell": "^2.0.1", + "html-webpack-plugin": "^2.28.0", "http-proxy": "^1.16.0", "imports-loader": "^0.7.0", "jquery": "^2.2.0", @@ -107,15 +107,15 @@ "velocity-animate": "^1.4.2", "velocity-react": "1.2.0", "visualizeRevTree": "git+https://github.com/neojski/visualizeRevTree.git#gh-pages", - "webpack": "^1.12.12", - "webpack-dev-server": "^1.14.1", + "webpack": "~2.2.1", + "webpack-dev-server": "~2.4.1", "whatwg-fetch": "~2.0.1" }, "scripts": { "stylecheck": "eslint --ext=js,jsx .", "webpack:dev": "webpack --debug --progress --colors --config ./webpack.config.dev.js", "webpack:test": "webpack --debug --progress --colors --config ./webpack.config.test.js", - "webpack:release": "webpack --debug --progress --colors --config ./webpack.config.release.js", + "webpack:release": "webpack --optimize-minimize --debug --progress --colors --config ./webpack.config.release.js", "jest": "jest --config ./jest-config.json", "test": "grunt test && npm run jest", "phantomjs": "./node_modules/.bin/mocha-phantomjs --debug=false --ssl-protocol=sslv2 --web-security=false --ignore-ssl-errors=true ./test/runner.html", diff --git a/settings.json.default.json b/settings.json.default.json index 510f7f2d7..fde5dada0 100644 --- a/settings.json.default.json +++ b/settings.json.default.json @@ -17,13 +17,11 @@ ], "template": { "development": { - "src": "assets/index.underscore", + "src": "./assets/index.underscore", "dest": "dist/debug/index.html", "variables": { - "bundlejs": "/bundle.js", - "css": "./dashboard.assets/css/index.css", - "base": null, - "development": true + "title": "Project Fauxton", + "generationLabel": "Fauxton Dev" }, "app": { "root": "/", @@ -35,10 +33,8 @@ "src": "assets/index.underscore", "dest": "dist/debug/index.html", "variables": { - "bundlejs": "./dashboard.assets/js/BUNDLEJS_FILE", - "css": "./dashboard.assets/css/CSS_FILE", - "base": null, - "development": false + "title": "Project Fauxton", + "generationLabel": "Fauxton Release" }, "app": { "root": "/", @@ -50,10 +46,8 @@ "src": "assets/index.underscore", "dest": "dist/debug/index.html", "variables": { - "bundlejs": "./js/BUNDLEJS_FILE", - "css": "./css/CSS_FILE", - "base": null, - "development": false + "title": "Project Fauxton", + "generationLabel": "Fauxton Couchapp" }, "app": { "root": "/", diff --git a/tasks/fauxton.js b/tasks/fauxton.js index 3fbad30bc..e4c2f880d 100644 --- a/tasks/fauxton.js +++ b/tasks/fauxton.js @@ -15,14 +15,6 @@ module.exports = function (grunt) { fs = require('fs'), os = require('os'); - grunt.registerMultiTask('template', 'generates an html file from a specified template', function () { - var data = this.data, - _ = grunt.util._, - tmpl = _.template(grunt.file.read(data.src), null, data.variables); - - grunt.file.write(data.dest, tmpl(data.variables)); - }); - grunt.registerMultiTask('get_deps', 'Fetch external dependencies', function () { grunt.log.writeln('Fetching external dependencies'); diff --git a/tasks/helper.js b/tasks/helper.js index 70d4e127d..d880ae5c0 100644 --- a/tasks/helper.js +++ b/tasks/helper.js @@ -16,26 +16,25 @@ var fs = require('fs'), exports.devServerPort = 8000; exports.couch = 'http://couch:5984/'; -exports.init = function (grunt) { - var _ = grunt.util._; +exports.init = function () { return { readSettingsFile: function () { - if (fs.existsSync("settings.json")) { - return grunt.file.readJSON("settings.json"); - } else if (fs.existsSync('settings.json.default.json')) { - return grunt.file.readJSON('settings.json.default.json'); + if (fs.existsSync(path.join(__dirname, "../settings.json"))) { + return require(path.join(__dirname, "../settings.json")); + } else if (fs.existsSync(path.join(__dirname, '../settings.json.default.json'))) { + return require(path.join(__dirname, '../settings.json.default.json')); } throw new Error('settings.json file missing'); }, readI18nFile: function () { - if (fs.existsSync('i18n.json')) { - return grunt.file.readJSON('i18n.json'); + if (fs.existsSync(path.join(__dirname, '../i18n.json'))) { + return require(path.join(__dirname, '../i18n.json')); } - if (fs.existsSync('i18n.json.default.json')) { - return grunt.file.readJSON('i18n.json.default.json'); + if (fs.existsSync(path.join(__dirname, '../i18n.json.default.json'))) { + return require(path.join(__dirname, '../i18n.json.default.json')); } throw new Error('i18n file missing'); @@ -46,9 +45,9 @@ exports.init = function (grunt) { }, getFileList: function (fileExtensions, defaults) { - return _.reduce(this.readSettingsFile().deps, function (files, dep) { + return this.readSettingsFile().deps.reduce((files, dep) => { if (dep.path) { - _.each(fileExtensions, function (fileExtension) { + fileExtensions.forEach(fileExtension => { files.push(path.join(dep.path, '**/*' + fileExtension)); }); } diff --git a/test/test.config.underscore b/test/test.config.underscore index 32a16a7f8..501c6f5d3 100644 --- a/test/test.config.underscore +++ b/test/test.config.underscore @@ -12,7 +12,7 @@ // License for the specific language governing permissions and limitations under // the License. // - +var Promise = require('bluebird'); require([ "url-polyfill", <% _.each(testFiles, function (test) {%> diff --git a/webpack.config.dev.js b/webpack.config.dev.js index ac734dbae..89d3dbd55 100644 --- a/webpack.config.dev.js +++ b/webpack.config.dev.js @@ -10,69 +10,102 @@ // License for the specific language governing permissions and limitations under // the License. const webpack = require('webpack'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); +const path = require('path'); +const settings = require('./tasks/helper') + .init() + .readSettingsFile() + .template + .development; module.exports = { - entry: [ - './app/main.js' //Our starting point for our development. - ], + entry: { + bundle: './app/main.js' //Our starting point for our development. + }, + + output: { + path: path.join(__dirname, '/dist/debug/'), + filename: 'dashboard.assets/js/[name].js' + }, + plugins: [ - new webpack.optimize.LimitChunkCountPlugin({maxChunks: 1}) + new webpack.optimize.LimitChunkCountPlugin({maxChunks: 1}), + new HtmlWebpackPlugin(Object.assign({ + template: settings.src, + title: 'Project Fauxton', + filename: 'index.html', + generationLabel: 'Fauxton Dev', + generationDate: new Date().toISOString() + }, settings.variables)), ], module: { - preLoaders: [ - { - test: /\.jsx?$/, - loaders: ['eslint'], - exclude: /node_modules/ - } - ], - loaders: [ + rules: [ + { + test: /\.jsx?$/, + enforce: "pre", + use: ['eslint-loader'], + exclude: /node_modules/ + }, { test: /\.jsx?$/, exclude: /node_modules/, - //loader: 'react-hot!babel' - loader: 'babel' + use: 'babel-loader' }, - { test: require.resolve("jquery"), - loader: "expose?$!expose?jQuery" + { + test: require.resolve('jquery'), + use: [{ + loader: 'expose-loader', + options: 'jQuery' + }, + { + loader: 'expose-loader', + options: '$' + }] }, - { test: require.resolve("backbone"), - loader: "expose?Backbone" + { + test: require.resolve("backbone"), + use: [{ + loader: 'expose-loader', + options: 'Backbone' + }] }, { test: /\.less$/, - loader: 'style!css!less' + use: [ + "style-loader", + "css-loader", + "less-loader" + ] + }, + { + test: /\.css$/, + use: [ + "style-loader", + "css-loader" + ] }, - { test: /\.css$/, loader: 'style!css' }, { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, - loader: 'url?limit=10000&mimetype=application/font-woff&name=dashboard.assets/fonts/[name].[ext]' + loader: 'url-loader?limit=10000&mimetype=application/font-woff&name=dashboard.assets/fonts/[name].[ext]' }, { - test: /\.woff2(\?\S*)?$/, loader: 'url?limit=10000&mimetype=application/font-woff2&name=dashboard.assets/fonts/[name].[ext]' + test: /\.woff2(\?\S*)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff2&name=dashboard.assets/fonts/[name].[ext]' }, { - test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-tff&name=dashboard.assets/fonts/[name].[ext]' + test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-tff&name=dashboard.assets/fonts/[name].[ext]' }, - { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/fonts/[name].[ext]' }, - { test: /\.swf(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/[name].[ext]' }, - { test: /\.png(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/img/[name].[ext]' }, - { test: /\.gif(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/img/[name].[ext]' }, - { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml&name=dashboard.assets/img/[name].[ext]' } + { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/fonts/[name].[ext]' }, + { test: /\.png(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/img/[name].[ext]' }, + { test: /\.gif(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/img/[name].[ext]' }, + { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml&name=dashboard.assets/img/[name].[ext]' } ] }, resolve: { - extensions: ['', '.js', '.jsx'], //We can use .js and React's .jsx files using Babel + extensions: ['*', '.js', '.jsx'], //We can use .js and React's .jsx files using Babel alias: { "bootstrap": "../assets/js/libs/bootstrap", "underscore": "lodash", } }, - output: { - path: __dirname + '/dist/debug', - publicPath: '/', - filename: 'bundle.js' //All our code is compiled into a single file called bundle.js - }, - devtool: 'source-map' }; diff --git a/webpack.config.release.js b/webpack.config.release.js index 0b71897bc..99316c93a 100644 --- a/webpack.config.release.js +++ b/webpack.config.release.js @@ -11,17 +11,23 @@ // the License. var webpack = require('webpack'); var ExtractTextPlugin = require("extract-text-webpack-plugin"); +var HtmlWebpackPlugin = require('html-webpack-plugin'); var path = require('path'); +const settings = require('./tasks/helper') + .init() + .readSettingsFile() + .template + .release; module.exports = { // Entry point for static analyzer: - entry: [ - './app/main.js' - ], + entry: { + bundle: './app/main.js' + }, output: { - path: path.join(__dirname, '/dist/release'), - filename: 'bundle.js' + path: path.join(__dirname, '/dist/release/'), + filename: 'dashboard.assets/js/[name].[chunkhash].js' }, plugins: [ @@ -34,13 +40,31 @@ module.exports = { // moment doesn't offer a modular API, so manually remove locale // see https://github.com/moment/moment/issues/2373 new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), - new webpack.optimize.DedupePlugin(), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false + }, + sourceMap: true + }), + new webpack.optimize.CommonsChunkPlugin({ + name: 'vendor', // Specify the common bundle's name. + minChunks: function (module) { + // this assumes your vendor imports exist in the node_modules directory + return module.context && module.context.indexOf('node_modules') !== -1; } }), - new ExtractTextPlugin("styles.css") + new webpack.optimize.CommonsChunkPlugin({ + name: "manifest", + minChunks: Infinity + }), + new HtmlWebpackPlugin(Object.assign({ + template: settings.src, + title: 'Project Fauxton', + filename: 'index.html', + generationLabel: 'Fauxton Release', + generationDate: new Date().toISOString() + }, settings.variables)), + new ExtractTextPlugin("dashboard.assets/css/styles.[chunkhash].css"), ], resolve: { @@ -49,51 +73,71 @@ module.exports = { }, module: { - preLoaders: [ - { - test: /\.jsx?$/, - loaders: ['eslint'], - exclude: /node_modules/ - } - ], loaders: [ { test: /\.jsx?$/, + enforce: "pre", + use: ['eslint-loader'], + exclude: /node_modules/ + }, + { + test: /\.jsx?$/, exclude: /node_modules/, - //loader: 'react-hot!babel' - loader: 'babel' + use: 'babel-loader' }, - { test: require.resolve("jquery"), - loader: "expose?$!expose?jQuery" + { + test: require.resolve('jquery'), + use: [{ + loader: 'expose-loader', + options: 'jQuery' + }, + { + loader: 'expose-loader', + options: '$' + }] }, - { test: require.resolve("backbone"), - loader: "expose?Backbone" + { + test: require.resolve("backbone"), + use: [{ + loader: 'expose-loader', + options: 'Backbone' + }] }, - { test: /\.less/, - loader: ExtractTextPlugin.extract("style-loader", "css-loader!less-loader", { + { + test: /\.less/, + use: ExtractTextPlugin.extract({ + fallback: "style-loader", + use: [ + "css-loader", + "less-loader" + ], publicPath: '../../' }), }, - { test: /\.css$/, loader: 'style!css' }, + { + test: /\.css$/, use: [ + 'style-loader', + 'css-loader' + ] + }, { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, - loader: 'url?limit=10000&mimetype=application/font-woff&name=dashboard.assets/fonts/[name].[ext]' + loader: 'url-loader?limit=10000&mimetype=application/font-woff&name=dashboard.assets/fonts/[name].[ext]' }, { - test: /\.woff2(\?\S*)?$/, loader: 'url?limit=10000&mimetype=application/font-woff2&name=dashboard.assets/fonts/[name].[ext]' + test: /\.woff2(\?\S*)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff2&name=dashboard.assets/fonts/[name].[ext]' }, { - test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-tff&name=dashboard.assets/fonts/[name].[ext]' + test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-tff&name=dashboard.assets/fonts/[name].[ext]' }, - { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/fonts/[name].[ext]' }, - { test: /\.swf(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/[name].[ext]' }, - { test: /\.png(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/img/[name].[ext]' }, - { test: /\.gif(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/img/[name].[ext]' }, - { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml&name=dashboard.assets/img/[name].[ext]' } + { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/fonts/[name].[ext]' }, + { test: /\.png(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/img/[name].[ext]' }, + { test: /\.gif(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/img/[name].[ext]' }, + { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml&name=dashboard.assets/img/[name].[ext]' } ] }, resolve: { - extensions: ['', '.js', '.jsx'], + extensions: ['*', '.js', '.jsx'], alias: { "underscore": "lodash", "bootstrap": "../assets/js/libs/bootstrap", diff --git a/webpack.config.test-dev.js b/webpack.config.test-dev.js index e24fbd173..cdbfefd0d 100644 --- a/webpack.config.test-dev.js +++ b/webpack.config.test-dev.js @@ -13,60 +13,84 @@ const webpack = require('webpack'); module.exports = { entry: [ - 'mocha!./test/dev.js', //Our starting point for our testing. + 'mocha-loader!./test/dev.js', //Our starting point for our testing. ], module: { - preLoaders: [ - { - test: /\.jsx?$/, - loaders: ['eslint'], - exclude: /node_modules/ - } - ], - loaders: [ + rules: [ + { + test: /\.jsx?$/, + enforce: "pre", + use: ['eslint-loader'], + exclude: /node_modules/ + }, { test: /\.jsx?$/, exclude: /node_modules/, - //loader: 'react-hot!babel' - loader: 'babel' + use: 'babel-loader' }, - { test: require.resolve("jquery"), - loader: "expose?$!expose?jQuery" - }, - { test: require.resolve("sinon"), - loader: "expose?sinon" - }, - { test: require.resolve("backbone"), - loader: "expose?Backbone" + { + test: require.resolve("jquery"), + use: [ + { + loader: 'expose-loader', + options: 'jQuery' + }, + { + loader: 'expose-loader', + options: '$' + }] + }, + { + test: require.resolve("backbone"), + use: [{ + loader: 'expose-loader', + options: 'Backbone' + }] + }, + { + test: require.resolve("sinon"), + use: [{ + loader: 'expose-loader', + options: 'sinon' + }] }, { test: require.resolve("react"), - loader: "imports?shim=es5-shim/es5-shim&sham=es5-shim/es5-sham" + loader: "imports-loader?shim=es5-shim/es5-shim&sham=es5-shim/es5-sham" }, { test: /\.less$/, - loader: 'style!css!less' + use: [ + "style-loader", + "css-loader", + "less-loader" + ] + }, + { + test: /\.css$/, + use: [ + "style-loader", + "css-loader" + ] }, - { test: /\.css$/, loader: 'style!css' }, { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, - loader: 'url?limit=10000&mimetype=application/font-woff&name=dashboard.assets/fonts/[name].[ext]' + loader: 'url-loader?limit=10000&mimetype=application/font-woff&name=dashboard.assets/fonts/[name].[ext]' }, { - test: /\.woff2(\?\S*)?$/, loader: 'url?limit=10000&mimetype=application/font-woff2&name=dashboard.assets/fonts/[name].[ext]' + test: /\.woff2(\?\S*)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff2&name=dashboard.assets/fonts/[name].[ext]' }, { - test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-tff&name=dashboard.assets/fonts/[name].[ext]' + test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-tff&name=dashboard.assets/fonts/[name].[ext]' }, - { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/fonts/[name].[ext]' }, - { test: /\.swf(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/[name].[ext]' }, - { test: /\.png(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/img/[name].[ext]' }, - { test: /\.gif(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/img/[name].[ext]' }, - { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml&name=dashboard.assets/img/[name].[ext]' } + { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/fonts/[name].[ext]' }, + { test: /\.png(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/img/[name].[ext]' }, + { test: /\.gif(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/img/[name].[ext]' }, + { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml&name=dashboard.assets/img/[name].[ext]' } ] }, resolve: { - extensions: ['', '.js', '.jsx'], //We can use .js and React's .jsx files using Babel + extensions: ['*', '.js', '.jsx'], //We can use .js and React's .jsx files using Babel alias: { "bootstrap": "../assets/js/libs/bootstrap", "underscore": "lodash" diff --git a/webpack.config.test.js b/webpack.config.test.js index 54a60bb74..8cb016f1b 100644 --- a/webpack.config.test.js +++ b/webpack.config.test.js @@ -16,64 +16,86 @@ module.exports = { './test/test.config.js' //Our starting point for our testing. ], module: { - preLoaders: [ - { - test: /\.jsx?$/, - loaders: ['eslint'], - exclude: /node_modules/ - } - ], - loaders: [ + rules: [ + { + test: /\.jsx?$/, + enforce: "pre", + use: ['eslint-loader'], + exclude: /node_modules/ + }, { test: /\.jsx?$/, exclude: /node_modules/, //loader: 'react-hot!babel' - loader: 'babel' + use: 'babel-loader' }, { - test: require.resolve("jquery"), - loader: "expose?$!expose?jQuery" + test: require.resolve('jquery'), + use: [ + { + loader: 'expose-loader', + options: 'jQuery' + }, + { + loader: 'expose-loader', + options: '$' + }] + }, + { + test: require.resolve("backbone"), + use: [{ + loader: 'expose-loader', + options: 'Backbone' + }] }, { test: require.resolve("sinon"), - loader: "expose?sinon" - }, - { - test: require.resolve("backbone"), - loader: "expose?Backbone" + use: [{ + loader: 'expose-loader', + options: 'sinon' + }] }, { test: require.resolve("url-polyfill"), - loader: "imports?this=>window" + use: "imports-loader?this=>window" }, { test: require.resolve("react"), - loader: "imports?shim=es5-shim/es5-shim&sham=es5-shim/es5-sham" + use: "imports-loader?shim=es5-shim/es5-shim&sham=es5-shim/es5-sham" }, { test: /\.less$/, - loader: 'style!css!less' + use: [ + "style-loader", + "css-loader", + "less-loader" + ] + }, + { + test: /\.css$/, + use: [ + "style-loader", + "css-loader" + ] }, - { test: /\.css$/, loader: 'style!css' }, { test: /\.woff(\?v=\d+\.\d+\.\d+)?$/, - loader: 'url?limit=10000&mimetype=application/font-woff&name=dashboard.assets/fonts/[name].[ext]' + loader: 'url-loader?limit=10000&mimetype=application/font-woff&name=dashboard.assets/fonts/[name].[ext]' }, { - test: /\.woff2(\?\S*)?$/, loader: 'url?limit=10000&mimetype=application/font-woff2&name=dashboard.assets/fonts/[name].[ext]' + test: /\.woff2(\?\S*)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-woff2&name=dashboard.assets/fonts/[name].[ext]' }, { - test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=application/font-tff&name=dashboard.assets/fonts/[name].[ext]' + test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=application/font-tff&name=dashboard.assets/fonts/[name].[ext]' }, - { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/fonts/[name].[ext]' }, - { test: /\.swf(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/[name].[ext]' }, - { test: /\.png(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/img/[name].[ext]' }, - { test: /\.gif(\?v=\d+\.\d+\.\d+)?$/, loader: 'file?name=dashboard.assets/img/[name].[ext]' }, - { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url?limit=10000&mimetype=image/svg+xml&name=dashboard.assets/img/[name].[ext]' } + { test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/fonts/[name].[ext]' }, + { test: /\.png(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/img/[name].[ext]' }, + { test: /\.gif(\?v=\d+\.\d+\.\d+)?$/, loader: 'file-loader?name=dashboard.assets/img/[name].[ext]' }, + { test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, loader: 'url-loader?limit=10000&mimetype=image/svg+xml&name=dashboard.assets/img/[name].[ext]' } ] }, resolve: { - extensions: ['', '.js', '.jsx'], //We can use .js and React's .jsx files using Babel + extensions: ['*', '.js', '.jsx'], //We can use .js and React's .jsx files using Babel alias: { "bootstrap": "../assets/js/libs/bootstrap", "underscore": "lodash",