diff --git a/pkg/interface/CONTRIBUTING.md b/pkg/interface/CONTRIBUTING.md index 8ef634361c..ad81ad1f3e 100644 --- a/pkg/interface/CONTRIBUTING.md +++ b/pkg/interface/CONTRIBUTING.md @@ -88,6 +88,23 @@ hygiene][contributing]. [contributing]: /CONTRIBUTING.md#git-practice [arvo]: /pkg/arvo [interface]:/pkg/interface +### Webpack Dev Server + +If you are only intending to test the JS on one ship, then you may use the +webpack dev server to allow for HMR. To do this, uncomment the `URL` property +in your urbitrc and replace it with the URL of the urbit that you are testing +on. e.g. + +```javascript +module.exports = { + URL: 'http://localhost:80' +} +``` + +and then run `npm run start` as usual. You can then access a hot reloaded +version of the interface at `http://localhost:9000`. Note that this also works +for non-locally hosted ships. + ## Linting The Urbit interface uses Eslint to lint the JavaScript code. To install the diff --git a/pkg/interface/config/urbitrc-sample b/pkg/interface/config/urbitrc-sample index 1315a1d062..1b6a6ec237 100644 --- a/pkg/interface/config/urbitrc-sample +++ b/pkg/interface/config/urbitrc-sample @@ -2,5 +2,6 @@ module.exports = { URBIT_PIERS: [ "/Users/user/ships/zod/home", ], - herb: false + herb: false, + // URL: 'http://localhost:80' }; diff --git a/pkg/interface/config/webpack.dev.js b/pkg/interface/config/webpack.dev.js index 356576d08c..dd9568edea 100644 --- a/pkg/interface/config/webpack.dev.js +++ b/pkg/interface/config/webpack.dev.js @@ -60,6 +60,32 @@ class UrbitShipPlugin { } } +let devServer = { + contentBase: path.join(__dirname, '../dist'), + hot: true, + port: 9000, + historyApiFallback: true +} + +if(urbitrc.URL) { + devServer = { + ...devServer, + index: '', + proxy: { + '/~landscape/js/index.js': { + target: 'http://localhost:9000', + pathRewrite: (req, path) => '/index.js' + }, + '**': { + target: urbitrc.URL, + // ensure proxy doesn't timeout channels + proxyTimeout: 0 + } + } + } +} + + module.exports = { mode: 'development', entry: { @@ -76,7 +102,8 @@ module.exports = { plugins: [ '@babel/plugin-proposal-object-rest-spread', '@babel/plugin-proposal-optional-chaining', - '@babel/plugin-proposal-class-properties' + '@babel/plugin-proposal-class-properties', + 'react-hot-loader/babel' ] } }, @@ -99,12 +126,7 @@ module.exports = { extensions: ['.js', '.ts', '.tsx'] }, devtool: 'inline-source-map', - devServer: { - contentBase: path.join(__dirname, '../dist'), - hot: true, - port: 9000, - historyApiFallback: true - }, + devServer: devServer, plugins: [ new UrbitShipPlugin(urbitrc) // new CleanWebpackPlugin(), diff --git a/pkg/interface/package-lock.json b/pkg/interface/package-lock.json index 0fa9a66616..3552f5495b 100644 --- a/pkg/interface/package-lock.json +++ b/pkg/interface/package-lock.json @@ -3510,6 +3510,12 @@ "entities": "^2.0.0" } }, + "dom-walk": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz", + "integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w==", + "dev": true + }, "domain-browser": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", @@ -4761,6 +4767,16 @@ "is-glob": "^4.0.1" } }, + "global": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/global/-/global-4.4.0.tgz", + "integrity": "sha512-wv/LAoHdRE3BeTGz53FAamhGlPLhlssK45usmGFThIi4XqnBmjKQ16u+RNbP7WvigRZDxUsM0J3gcQ5yicaL0w==", + "dev": true, + "requires": { + "min-document": "^2.19.0", + "process": "^0.11.10" + } + }, "global-modules": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-2.0.0.tgz", @@ -6113,6 +6129,15 @@ "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", "dev": true }, + "min-document": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/min-document/-/min-document-2.19.0.tgz", + "integrity": "sha1-e9KC4/WELtKVu3SM3Z8f+iyCRoU=", + "dev": true, + "requires": { + "dom-walk": "^0.1.0" + } + }, "mini-create-react-context": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/mini-create-react-context/-/mini-create-react-context-0.3.2.tgz", @@ -7327,11 +7352,41 @@ "resolved": "https://registry.npmjs.org/react-fast-compare/-/react-fast-compare-2.0.4.tgz", "integrity": "sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==" }, + "react-hot-loader": { + "version": "4.12.21", + "resolved": "https://registry.npmjs.org/react-hot-loader/-/react-hot-loader-4.12.21.tgz", + "integrity": "sha512-Ynxa6ROfWUeKWsTHxsrL2KMzujxJVPjs385lmB2t5cHUxdoRPGind9F00tOkdc1l5WBleOF4XEAMILY1KPIIDA==", + "dev": true, + "requires": { + "fast-levenshtein": "^2.0.6", + "global": "^4.3.0", + "hoist-non-react-statics": "^3.3.0", + "loader-utils": "^1.1.0", + "prop-types": "^15.6.1", + "react-lifecycles-compat": "^3.0.4", + "shallowequal": "^1.1.0", + "source-map": "^0.7.3" + }, + "dependencies": { + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + } + } + }, "react-is": { "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" }, + "react-lifecycles-compat": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz", + "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==", + "dev": true + }, "react-markdown": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/react-markdown/-/react-markdown-4.3.1.tgz", diff --git a/pkg/interface/package.json b/pkg/interface/package.json index 690f34bfe9..4f85e8c21e 100644 --- a/pkg/interface/package.json +++ b/pkg/interface/package.json @@ -46,6 +46,7 @@ "eslint-plugin-react": "^7.19.0", "file-loader": "^6.0.0", "html-webpack-plugin": "^4.2.0", + "react-hot-loader": "^4.12.21", "sass": "^1.26.5", "sass-loader": "^8.0.2", "webpack": "^4.43.0", diff --git a/pkg/interface/src/App.js b/pkg/interface/src/App.js index 7e2e62afb2..a34223d28c 100644 --- a/pkg/interface/src/App.js +++ b/pkg/interface/src/App.js @@ -1,3 +1,5 @@ +import { hot } from 'react-hot-loader/root'; +import 'react-hot-loader'; import * as React from 'react'; import { BrowserRouter as Router, Route, withRouter, Switch } from 'react-router-dom'; import styled, { ThemeProvider, createGlobalStyle } from 'styled-components'; @@ -45,7 +47,7 @@ const Content = styled.div` const StatusBarWithRouter = withRouter(StatusBar); -export default class App extends React.Component { +class App extends React.Component { constructor(props) { super(props); this.ship = window.ship; @@ -152,3 +154,5 @@ export default class App extends React.Component { } } +export default process.env.NODE_ENV === 'production' ? App : hot(App); +