diff --git a/lib/config.js b/lib/config.js index 8029df9..d2f2198 100644 --- a/lib/config.js +++ b/lib/config.js @@ -5,7 +5,6 @@ const union = require('lodash.union') const merge = require('lodash.merge') const {accessSync} = require('fs') const hygienist = require('hygienist-middleware') -const BrowserSyncPlugin = require('browser-sync-webpack-plugin') const SpikePlugin = require('./plugin') const SpikeUtils = require('spike-util') @@ -63,7 +62,6 @@ module.exports = class Config { module: Joi.object().default().keys({ rules: Joi.array().default([]) }), - devServer: Joi.func(), server: Joi.object().default().keys({ watchOptions: Joi.object().default().keys({ ignored: Joi.array().default('node_modules') @@ -141,9 +139,11 @@ module.exports = class Config { res.server.files = [{ match: allWatchedFiles, fn: (event, file) => { + console.log(event, file) const util = new SpikeUtils(this) const f = path.join(this.context, file.replace(p, '')) const opts = util.getSpikeOptions() + console.log(opts.files.all.indexOf(f)) if (opts.files.all.indexOf(f) < 0 && !util.isFileIgnored(f) && event !== 'addDir') { opts.project.watcher.watch([], [], [f]) } @@ -185,9 +185,7 @@ module.exports = class Config { } // this is sometimes necessary for webpackjsonp loads in old browsers - if (opts.outputPublicPath) { - this.output.publicPath = opts.outputPublicPath - } + this.output.publicPath = opts.outputPublicPath || this.output.path this.resolveLoader = { modules: [ @@ -239,16 +237,19 @@ module.exports = class Config { const util = new SpikeUtils(this) const spikePlugin = new SpikePlugin(util, spike) + const server2 = (_, bs) => { + if (bs.utils.devIp.length) { + spike.project.emit('info', `External IP: http://${bs.utils.devIp[0]}:${spike.server.port}`) + } + } + + // set custom dev server options + this.customDevServer = [opts.server, server2] this.plugins = [ ...opts.plugins, spikePlugin, - ...opts.afterSpikePlugins, - new BrowserSyncPlugin(opts.server, { callback: (_, bs) => { - if (bs.utils.devIp.length) { - spike.project.emit('info', `External IP: http://${bs.utils.devIp[0]}:${spike.server.port}`) - } - } }) + ...opts.afterSpikePlugins ] return this diff --git a/lib/index.js b/lib/index.js index cc6877a..a1619dd 100644 --- a/lib/index.js +++ b/lib/index.js @@ -13,6 +13,8 @@ const webpack = require('webpack') const rimraf = require('rimraf') const Sprout = require('sprout') const Joi = require('joi') +const browserSync = require('browser-sync') +const webpackDevMiddleware = require('webpack-dev-middleware') const {EventEmitter} = require('events') const Config = require('./config') const {Error, Warning} = require('./errors') @@ -26,7 +28,10 @@ const {Error, Warning} = require('./errors') class Spike extends EventEmitter { constructor (opts = {}) { super() - this.config = new Config(opts, this) + const config = new Config(opts, this) + this.devServer = config.customDevServer + delete config.customDevServer + this.config = config } /** @@ -51,12 +56,35 @@ class Spike extends EventEmitter { * @fires Spike#compile * @return {Object} watch id, webpack watcher */ + watch (opts = {}) { const id = uuid() this.compiler = webpack(this.config) - const watcher = this.compiler.watch(opts, compileCallback.bind(this, id)) - this.watcher = watcher - return {id, watcher} + + // add webpack dev middleware + const devMiddleware = webpackDevMiddleware(this.compiler, { + publicPath: this.config.output.publicPath, + stats: false, + overlay: true, + watchOptions: opts, + quiet: true, + compilerCallback: compileCallback.bind(this, id) + }) + this.devServer[0].middleware.unshift(devMiddleware) + + // TODO: A couple issues here. First, for some reason the watcher + // is not picking up new files, although it's detecting changes to + // existing files. Second, it's not writing the public folder. + // These changes are confusing as we're using the same thing exactly + // under the hood, but we'll figure it out! + + // run browsersync server + if (!this.browserSync) this.browserSync = browserSync.create() + this.browserSync.init(this.devServer[0], this.devServer[1]) + + // return the middleware watcher and id + this.watcher = devMiddleware.watcher + return {id, watcher: this.watcher} } /** @@ -165,9 +193,7 @@ function npmInstall (opts) { * @fires Spike#compile */ function compileCallback (id, err, stats) { - if (err) { - return this.emit('error', new Error({ id, err })) - } + if (err) { return this.emit('error', new Error({ id, err })) } // Webpack "soft errors" are classified as warnings in spike. An error is // an error. If it doesn't break the build, it's a warning. const cstats = stats.compilation @@ -178,7 +204,6 @@ function compileCallback (id, err, stats) { if (cstats.warnings.length) { this.emit('warning', new Warning({ id, err: cstats.warnings[0] })) } - this.emit('compile', {id, stats}) } diff --git a/package.json b/package.json index 700fc51..93699d2 100644 --- a/package.json +++ b/package.json @@ -29,10 +29,11 @@ "spike-util": "^1.3.0", "sprout": "^1.2.1", "webpack": "^3.2.0", + "webpack-dev-middleware": "^1.11.0", "when": "^3.7.8" }, "devDependencies": { - "ava": "^0.20.0", + "ava": "^0.21.0", "chalk": "^2.0.1", "coveralls": "^2.13.1", "husky": "^0.14.3", diff --git a/test/fixtures/watch/index.js b/test/fixtures/watch/index.js new file mode 100644 index 0000000..e69de29 diff --git a/test/watch.js b/test/watch.js index 4f6c4d1..db3ee91 100644 --- a/test/watch.js +++ b/test/watch.js @@ -7,7 +7,8 @@ const {fixturesPath} = require('./_helpers') test.cb('watches the project, reloads on modification', (t) => { const project = new Spike({ root: path.join(fixturesPath, 'watch'), - server: { open: false } + server: { open: false }, + entry: { main: './index.js' } }) let i = 0 @@ -32,7 +33,8 @@ test.cb('watches the project, reloads on modification', (t) => { test.cb('incorporates new file when added while watching', (t) => { const project = new Spike({ root: path.join(fixturesPath, 'watch'), - server: { open: false } + server: { open: false }, + entry: { main: './index.js' } }) let i = 0 const testFile = path.join(fixturesPath, 'watch/test.html') diff --git a/yarn.lock b/yarn.lock index 4fa8433..234b4e1 100644 --- a/yarn.lock +++ b/yarn.lock @@ -324,9 +324,9 @@ ava-init@^0.2.0: read-pkg-up "^2.0.0" write-pkg "^2.0.0" -ava@^0.20.0: - version "0.20.0" - resolved "https://registry.yarnpkg.com/ava/-/ava-0.20.0.tgz#bdc0dd36453d7255e9f733305ab370c248381e41" +ava@^0.21.0: + version "0.21.0" + resolved "https://registry.yarnpkg.com/ava/-/ava-0.21.0.tgz#cd8d8ea3546f57150dea38548b9f72f8ca583d29" dependencies: "@ava/babel-preset-stage-4" "^1.1.0" "@ava/babel-preset-transform-test-files" "^3.0.0" @@ -343,7 +343,7 @@ ava@^0.20.0: babel-core "^6.17.0" bluebird "^3.0.0" caching-transform "^1.0.0" - chalk "^1.0.0" + chalk "^2.0.1" chokidar "^1.4.2" clean-stack "^1.1.1" clean-yaml-object "^0.1.0" @@ -353,7 +353,7 @@ ava@^0.20.0: co-with-promise "^4.6.0" code-excerpt "^2.1.0" common-path-prefix "^1.0.0" - concordance "^2.0.0" + concordance "^3.0.0" convert-source-map "^1.2.0" core-assert "^0.2.0" currently-unhandled "^0.4.1" @@ -362,7 +362,7 @@ ava@^0.20.0: empower-core "^0.6.1" equal-length "^1.0.0" figures "^2.0.0" - find-cache-dir "^0.1.1" + find-cache-dir "^1.0.0" fn-name "^2.0.0" get-port "^3.0.0" globby "^6.0.0" @@ -384,25 +384,26 @@ ava@^0.20.0: lodash.flatten "^4.2.0" loud-rejection "^1.2.0" make-dir "^1.0.0" - matcher "^0.1.1" + matcher "^1.0.0" md5-hex "^2.0.0" meow "^3.7.0" - ms "^1.0.0" + ms "^2.0.0" multimatch "^2.1.0" observable-to-promise "^0.5.0" - option-chain "^0.1.0" + option-chain "^1.0.0" package-hash "^2.0.0" pkg-conf "^2.0.0" plur "^2.0.0" pretty-ms "^2.0.0" require-precompiled "^0.1.0" - resolve-cwd "^1.0.0" + resolve-cwd "^2.0.0" + safe-buffer "^5.1.1" slash "^1.0.0" source-map-support "^0.4.0" stack-utils "^1.0.0" - strip-ansi "^3.0.1" + strip-ansi "^4.0.0" strip-bom-buf "^1.0.0" - supports-color "^3.2.3" + supports-color "^4.0.0" time-require "^0.1.2" trim-off-newlines "^1.0.1" unique-temp-dir "^1.0.0" @@ -1299,10 +1300,11 @@ concat-stream@^1.5.0, concat-stream@^1.5.2: readable-stream "^2.2.2" typedarray "^0.0.6" -concordance@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/concordance/-/concordance-2.0.0.tgz#c3c5dbffa83c29537df202bded8fa1d6aa94e805" +concordance@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/concordance/-/concordance-3.0.0.tgz#b2286af54405fc995fc7345b0b106d8dd073cb29" dependencies: + date-time "^2.1.0" esutils "^2.0.2" fast-diff "^1.1.1" function-name-support "^0.2.0" @@ -1311,7 +1313,6 @@ concordance@^2.0.0: lodash.flattendeep "^4.4.0" lodash.merge "^4.6.0" md5-hex "^2.0.0" - moment "^2.18.1" semver "^5.3.0" well-known-symbols "^1.0.0" @@ -1516,6 +1517,12 @@ date-time@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/date-time/-/date-time-0.1.1.tgz#ed2f6d93d9790ce2fd66d5b5ff3edd5bbcbf3b07" +date-time@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/date-time/-/date-time-2.1.0.tgz#0286d1b4c769633b3ca13e1e62558d2dbdc2eba2" + dependencies: + time-zone "^1.0.0" + debug-log@^1.0.0, debug-log@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" @@ -3467,9 +3474,9 @@ map-visit@^0.1.5: lazy-cache "^2.0.1" object-visit "^0.3.4" -matcher@^0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/matcher/-/matcher-0.1.2.tgz#ef20cbde64c24c50cc61af5b83ee0b1b8ff00101" +matcher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/matcher/-/matcher-1.0.0.tgz#aaf0c4816eb69b92094674175625f3466b0e3e19" dependencies: escape-string-regexp "^1.0.4" @@ -3588,6 +3595,10 @@ mime@1.3.4, "mime@>= 0.0.1": version "1.3.4" resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" +mime@^1.3.4: + version "1.3.6" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0" + mimic-fn@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" @@ -3637,10 +3648,6 @@ mkdirp@0.3.0: dependencies: minimist "0.0.8" -moment@^2.18.1: - version "2.18.1" - resolved "https://registry.yarnpkg.com/moment/-/moment-2.18.1.tgz#c36193dd3ce1c2eed2adb7c802dbbc77a81b1c0f" - ms@0.7.1: version "0.7.1" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" @@ -3653,11 +3660,11 @@ ms@0.7.3: version "0.7.3" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.3.tgz#708155a5e44e33f5fd0fc53e81d0d40a91be1fff" -ms@1.0.0, ms@^1.0.0: +ms@1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-1.0.0.tgz#59adcd22edc543f7b5381862d31387b1f4bc9473" -ms@2.0.0: +ms@2.0.0, ms@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -3952,11 +3959,9 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -option-chain@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/option-chain/-/option-chain-0.1.1.tgz#e9b811e006f1c0f54802f28295bfc8970f8dcfbd" - dependencies: - object-assign "^4.0.1" +option-chain@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/option-chain/-/option-chain-1.0.0.tgz#938d73bd4e1783f948d34023644ada23669e30f2" optionator@^0.8.2: version "0.8.2" @@ -4427,7 +4432,7 @@ randombytes@^2.0.0, randombytes@^2.0.1: dependencies: safe-buffer "^5.1.0" -range-parser@~1.2.0: +range-parser@^1.0.3, range-parser@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" @@ -4757,12 +4762,6 @@ reshape@^0.4.1: reshape-parser "^0.2.1" when "^3.7.7" -resolve-cwd@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-1.0.0.tgz#4eaeea41ed040d1702457df64a42b2b07d246f9f" - dependencies: - resolve-from "^2.0.0" - resolve-cwd@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" @@ -4849,7 +4848,7 @@ rx@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.1.tgz#893312af69b2123def71f57889001671eeb2c853" @@ -5356,7 +5355,7 @@ supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" -supports-color@^3.1.0, supports-color@^3.1.2, supports-color@^3.2.3: +supports-color@^3.1.0, supports-color@^3.1.2: version "3.2.3" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" dependencies: @@ -5459,6 +5458,10 @@ time-require@^0.1.2: pretty-ms "^0.2.1" text-table "^0.2.0" +time-zone@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/time-zone/-/time-zone-1.0.0.tgz#99c5bf55958966af6d06d83bdf3800dc82faec5d" + timed-out@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/timed-out/-/timed-out-4.0.1.tgz#f32eacac5a175bea25d7fab565ab3ed8741ef56f" @@ -5749,6 +5752,15 @@ watchpack@^1.3.1: chokidar "^1.4.3" graceful-fs "^4.1.2" +webpack-dev-middleware@^1.11.0: + version "1.11.0" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.11.0.tgz#09691d0973a30ad1f82ac73a12e2087f0a4754f9" + dependencies: + memory-fs "~0.4.1" + mime "^1.3.4" + path-is-absolute "^1.0.0" + range-parser "^1.0.3" + webpack-sources@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.0.1.tgz#c7356436a4d13123be2e2426a05d1dad9cbe65cf"