diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..4bbd7c2 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,5 @@ +module.exports = { + "env": { + "es6": true + } +}; diff --git a/README.md b/README.md index 27a487a..9377001 100644 --- a/README.md +++ b/README.md @@ -103,7 +103,10 @@ module.exports = { } ``` -6. The following line in the entry JS file (e.g. main.js file): +6. The following line in the entry JS file (e.g. main.js file) to change + the public URL of the output directory when referenced in a browser. +During development it uses your `local` URL and on production it uses +Shopify's CDN. ```javascript __webpack_public_path__ = BRRL_PATH(BRRL_PUBLIC_PATH, BRRL_PROXY) // eslint-disable-line camelcase @@ -113,7 +116,7 @@ __webpack_public_path__ = BRRL_PATH(BRRL_PUBLIC_PATH, BRRL_PROXY) // eslint-disa ```liquid In the head: {% if settings.is_dev_mode %} - {{ '/dev/main.js' | script_tag }} + {{ 'https://localhost:3000/main.js' | script_tag }} {% else %} {{ 'main.css' | asset_url | stylesheet_tag }} {% endif %} diff --git a/lib/configure.js b/lib/configure.js index baac39c..958be35 100644 --- a/lib/configure.js +++ b/lib/configure.js @@ -1,6 +1,7 @@ const path = require('path') const fs = require('fs') const yaml = require('js-yaml') +const portFinderSync = require('portfinder-sync') const Err = require('./error') class Configure { @@ -19,6 +20,7 @@ class Configure { this.ymlFile = false this.defaults = Object.assign({}, { publicPath: '/dev', + port: 3000, local: 'localhost', dist: `${this.cwd}/dist`, theme_id: '', @@ -93,6 +95,7 @@ class Configure { } this.checkProxyTarget() + this.checkPort() this.checkPublicPath() this.checkDist() } @@ -108,9 +111,13 @@ class Configure { } } + checkPort () { + this.port = portFinderSync.getPort(this.defaults.port) + } + checkPublicPath () { if (this.shopify) { - this.publicPath = this.defaults.publicPath + this.publicPath = `https://${this.defaults.local}:${this.port}/` } else { const uri = this.webpack.output.path.split('/wp-content/')[1] this.publicPath = `/wp-content/${uri}` diff --git a/lib/hot-client.js b/lib/hot-client.js new file mode 100644 index 0000000..5dd748d --- /dev/null +++ b/lib/hot-client.js @@ -0,0 +1,16 @@ +/* eslint-disable */ +/* global __webpack_public_path__ window */ +// remove trailing slash from webpack public path +// see https://github.com/glenjamin/webpack-hot-middleware/issues/154 +const tmpPublicPath = __webpack_public_path__ +__webpack_public_path__ = __webpack_public_path__.replace(/\/$/, '') +const client = require('webpack-hot-middleware/client?dynamicPublicPath=true&reload=true') +// and add the trailing slash again so we don't run into issue with webpack itself... +__webpack_public_path__ = tmpPublicPath + +client.subscribe((event) => { + if (event.action === 'shopify_upload_finished') { + // Reload the page + window.location.reload() + } +}); diff --git a/lib/mutator.js b/lib/mutator.js index 1f6c457..e023a40 100644 --- a/lib/mutator.js +++ b/lib/mutator.js @@ -130,7 +130,7 @@ class Mutator { fs.copySync(path, `${dest.absolute}`) if (upload) { sendToShopify('upload', dest.relative, e => { - bs.reload() + bs.emitter.emit('shopify_upload_finished') resolve() }) } else { @@ -170,7 +170,7 @@ class Mutator { if (upload) { sendToShopify('upload', `/dist/config/settings_schema.json`, () => { - bs.reload() + bs.emitter.emit('shopify_upload_finished') resolve() }) } else { diff --git a/lib/watcher.js b/lib/watcher.js index d7c9a4c..c050a75 100644 --- a/lib/watcher.js +++ b/lib/watcher.js @@ -15,6 +15,7 @@ class Watcher { constructor() { this.compiler = Webpack(true).compiler + this.webpackHotMiddleware = WHM(this.compiler) this.copy() this.serve() @@ -38,7 +39,7 @@ class Watcher { } }), ...(config.get('hmr') ? [ - WHM(this.compiler) + this.webpackHotMiddleware ] : []) ], proxyReq: [ @@ -58,13 +59,20 @@ class Watcher { }, open: (this.isLocalhost() ? 'internal' : 'external'), host: config.get('local'), + port: config.get('port'), https: this.getSSL(), - notify: false + notify: true } } serve () { bs.init(this.getServerConfig()) + bs.emitter.on('shopify_upload_finished', () => { + // Notify the HMR client that we finished uploading files to Shopify + this.webpackHotMiddleware.publish({ + action: 'shopify_upload_finished' + }) + }) } copy () { diff --git a/lib/webpack.js b/lib/webpack.js index 0afd370..d9b6a97 100644 --- a/lib/webpack.js +++ b/lib/webpack.js @@ -7,7 +7,7 @@ const Err = require('./error') class Webpacker { constructor (watching = false) { this.watching = watching - this.hmr = 'webpack-hot-middleware/client?reload=true' + this.hmr = path.resolve(__dirname, 'hot-client.js') this.getConfig() this.prepareDevtool() @@ -100,13 +100,16 @@ class Webpacker { BRRL_VERSION: JSON.stringify(config.get('package').version), BRRL_PROXY: JSON.stringify(config.get('local')), BRRL_PATH: function(path, proxy) { + // use document.currentScript to know the currently processed JS file + // see https://github.com/vuejs/vue-cli/commit/5b1709abf010413b2f0b3d1a94ebb9577218c051 + const currentScript = window.document.currentScript; if (!proxy) { proxy = 'localhost'; }; - if (document.location.hostname === proxy) { + if (new URL(currentScript.src).hostname === proxy) { return path; } else { - return SHOPIFY_CDN; + return window.SHOPIFY_CDN; }; } }) diff --git a/package-lock.json b/package-lock.json index 4496c80..e591d30 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4030,6 +4030,61 @@ "pinkie": "^2.0.0" } }, + "portfinder": { + "version": "1.0.28", + "resolved": "https://registry.npmjs.org/portfinder/-/portfinder-1.0.28.tgz", + "integrity": "sha512-Se+2isanIcEqf2XMHjyUKskczxbPH7dQnlMjXX6+dybayyHvAf/TCgyMRlzf/B6QDhAEFOGes0pzRo3by4AbMA==", + "requires": { + "async": "^2.6.2", + "debug": "^3.1.1", + "mkdirp": "^0.5.5" + }, + "dependencies": { + "async": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", + "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", + "requires": { + "lodash": "^4.17.14" + } + }, + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + }, + "minimist": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", + "integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==" + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "requires": { + "minimist": "^1.2.5" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "portfinder-sync": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/portfinder-sync/-/portfinder-sync-0.0.2.tgz", + "integrity": "sha1-bjQJpzpxhDbeBTrJSThTUMqr2KI=", + "requires": { + "minimist": "^1.2.0", + "portfinder": "^1.0.10" + } + }, "portscanner": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.1.1.tgz", diff --git a/package.json b/package.json index 546e9ef..880081e 100644 --- a/package.json +++ b/package.json @@ -23,6 +23,7 @@ "js-yaml": "^3.12.0", "minimatch": "^3.0.4", "moment-timezone": "^0.5.21", + "portfinder-sync": "0.0.2", "shopify-node-api": "^1.8.0", "webpack-dev-middleware": "^3.1.3", "webpack-hot-middleware": "^2.22.3"