Merge branch 'develop' into matthew/postcss
						commit
						14eec6d982
					
				
							
								
								
									
										29
									
								
								CHANGELOG.md
								
								
								
								
							
							
						
						
									
										29
									
								
								CHANGELOG.md
								
								
								
								
							|  | @ -1,3 +1,32 @@ | |||
| Changes in [0.9.6](https://github.com/vector-im/riot-web/releases/tag/v0.9.6) (2017-01-16) | ||||
| ========================================================================================== | ||||
| [Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.6-rc.1...v0.9.6) | ||||
| 
 | ||||
|  * Update to matrix-js-sdk 0.9.6 for video calling fix | ||||
| 
 | ||||
| Changes in [0.9.6-rc.1](https://github.com/vector-im/riot-web/releases/tag/v0.9.6-rc.1) (2017-01-13) | ||||
| ==================================================================================================== | ||||
| [Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.5...v0.9.6-rc.1) | ||||
| 
 | ||||
|  * Build the js-sdk in the CI script | ||||
|    [\#2920](https://github.com/vector-im/riot-web/pull/2920) | ||||
|  * Hopefully fix Windows shortcuts | ||||
|    [\#2917](https://github.com/vector-im/riot-web/pull/2917) | ||||
|  * Update README now the js-sdk has a transpile step | ||||
|    [\#2921](https://github.com/vector-im/riot-web/pull/2921) | ||||
|  * Use the role for 'toggle dev tools' | ||||
|    [\#2915](https://github.com/vector-im/riot-web/pull/2915) | ||||
|  * Enable screen sharing easter-egg in desktop app | ||||
|    [\#2909](https://github.com/vector-im/riot-web/pull/2909) | ||||
|  * make electron send email validation URLs with a nextlink of riot.im | ||||
|    [\#2808](https://github.com/vector-im/riot-web/pull/2808) | ||||
|  * add Debian Stretch install steps to readme | ||||
|    [\#2809](https://github.com/vector-im/riot-web/pull/2809) | ||||
|  * Update desktop build instructions fixes #2792 | ||||
|    [\#2793](https://github.com/vector-im/riot-web/pull/2793) | ||||
|  * CSS for the delete threepid button | ||||
|    [\#2784](https://github.com/vector-im/riot-web/pull/2784) | ||||
| 
 | ||||
| Changes in [0.9.5](https://github.com/vector-im/riot-web/releases/tag/v0.9.5) (2016-12-24) | ||||
| ========================================================================================== | ||||
| [Full Changelog](https://github.com/vector-im/riot-web/compare/v0.9.4...v0.9.5) | ||||
|  |  | |||
							
								
								
									
										18
									
								
								README.md
								
								
								
								
							
							
						
						
									
										18
									
								
								README.md
								
								
								
								
							|  | @ -14,7 +14,7 @@ https://riot.im/develop for those who like living dangerously. | |||
| To host your own copy of Riot, the quickest bet is to use a pre-built | ||||
| released version of Riot: | ||||
| 
 | ||||
| 1. Download the latest version from https://github.com/vector-im/vector-web/releases | ||||
| 1. Download the latest version from https://github.com/vector-im/riot-web/releases | ||||
| 1. Untar the tarball on your web server | ||||
| 1. Move (or symlink) the vector-x.x.x directory to an appropriate name | ||||
| 1. If desired, copy `config.sample.json` to `config.json` and edit it | ||||
|  | @ -44,7 +44,7 @@ access to Riot (or other apps) due to sharing the same domain. | |||
| 
 | ||||
| We have put some coarse mitigations into place to try to protect against this | ||||
| situation, but it's still not good practice to do it in the first place.  See | ||||
| https://github.com/vector-im/vector-web/issues/1977 for more details. | ||||
| https://github.com/vector-im/riot-web/issues/1977 for more details. | ||||
| 
 | ||||
| Building From Source | ||||
| ==================== | ||||
|  | @ -53,8 +53,8 @@ Riot is a modular webapp built with modern ES6 and requires a npm build system | |||
| to build. | ||||
| 
 | ||||
| 1. Install or update `node.js` so that your `npm` is at least at version `2.0.0` | ||||
| 1. Clone the repo: `git clone https://github.com/vector-im/vector-web.git` | ||||
| 1. Switch to the vector-web directory: `cd vector-web` | ||||
| 1. Clone the repo: `git clone https://github.com/vector-im/riot-web.git` | ||||
| 1. Switch to the riot-web directory: `cd riot-web` | ||||
| 1. Install the prerequisites: `npm install` | ||||
| 1. If you are using the `develop` branch of vector-web, you will probably need | ||||
|    to rebuild some of the dependencies, due to | ||||
|  | @ -109,7 +109,7 @@ Running as a Desktop app | |||
| ======================== | ||||
| 
 | ||||
| Riot can also be run as a desktop app, wrapped in electron. You can download a | ||||
| pre-built version from https://riot.im/download/desktop/ or, if you prefer, | ||||
| pre-built version from https://riot.im/desktop.html or, if you prefer, | ||||
| built it yourself. | ||||
| 
 | ||||
| To run as a desktop app: | ||||
|  | @ -179,13 +179,13 @@ the `component-index.js` for the app (used in future for skinning) | |||
| development on Riot forcing `matrix-react-sdk` to move fast at the expense of | ||||
| maintaining a clear abstraction between the two.**  Hacking on Riot inevitably | ||||
| means hacking equally on `matrix-react-sdk`, and there are bits of | ||||
| `matrix-react-sdk` behaviour incorrectly residing in the `vector-web` project | ||||
| `matrix-react-sdk` behaviour incorrectly residing in the `riot-web` project | ||||
| (e.g. matrix-react-sdk specific CSS), and a bunch of Riot specific behaviour | ||||
| in the `matrix-react-sdk` (grep for `vector` / `riot`).  This separation problem will be | ||||
| solved asap once development on Riot (and thus matrix-react-sdk) has | ||||
| stabilised.  Until then, the two projects should basically be considered as a | ||||
| single unit.  In particular, `matrix-react-sdk` issues are currently filed | ||||
| against `vector-web` in github. | ||||
| against `riot-web` in github. | ||||
| 
 | ||||
| Please note that Riot is intended to run correctly without access to the public | ||||
| internet.  So please don't depend on resources (JS libs, CSS, images, fonts) | ||||
|  | @ -220,8 +220,8 @@ Then similarly with `matrix-react-sdk`: | |||
| 
 | ||||
| Finally, build and start Riot itself: | ||||
| 
 | ||||
| 1. `git clone git@github.com:vector-im/vector-web.git` | ||||
| 1. `cd vector-web` | ||||
| 1. `git clone git@github.com:vector-im/riot-web.git` | ||||
| 1. `cd riot-web` | ||||
| 1. `git checkout develop` | ||||
| 1. `npm install` | ||||
| 1. `rm -r node_modules/matrix-js-sdk; ln -s ../../matrix-js-sdk node_modules/` | ||||
|  |  | |||
|  | @ -112,7 +112,16 @@ function startAutoUpdate(update_base_url) { | |||
|         // 204 No Content. On windows it takes a base path and looks for
 | ||||
|         // files under that path.
 | ||||
|         if (process.platform == 'darwin') { | ||||
|             electron.autoUpdater.setFeedURL(update_base_url + 'macos/'); | ||||
|             // include the current version in the URL we hit. Electron doesn't add
 | ||||
|             // it anywhere (apart from the User-Agent) so it's up to us. We could
 | ||||
|             // (and previously did) just use the User-Agent, but this doesn't
 | ||||
|             // rely on NSURLConnection setting the User-Agent to what we expect,
 | ||||
|             // and also acts as a convenient cache-buster to ensure that when the
 | ||||
|             // app updates it always gets a fresh value to avoid update-looping.
 | ||||
|             electron.autoUpdater.setFeedURL( | ||||
|                 update_base_url + | ||||
|                 'macos/?localVersion=' + encodeURIComponent(electron.app.getVersion()) | ||||
|             ); | ||||
|         } else if (process.platform == 'win32') { | ||||
|             electron.autoUpdater.setFeedURL(update_base_url + 'win32/' + process.arch + '/'); | ||||
|         } else { | ||||
|  |  | |||
|  | @ -2,7 +2,7 @@ | |||
|   "name": "riot-web", | ||||
|   "productName": "Riot", | ||||
|   "main": "electron/src/electron-main.js", | ||||
|   "version": "0.9.5", | ||||
|   "version": "0.9.6", | ||||
|   "description": "A feature-rich client for Matrix.org", | ||||
|   "author": "Vector Creations Ltd.", | ||||
|   "repository": { | ||||
|  |  | |||
|  | @ -1,13 +1,32 @@ | |||
| #!/usr/bin/env python | ||||
| # | ||||
| # auto-deploy script for https://riot.im/develop | ||||
| # | ||||
| # Listens for HTTP hits. When it gets one, downloads the artifact from jenkins | ||||
| # and deploys it as the new version. | ||||
| # | ||||
| # Requires the following python packages: | ||||
| # | ||||
| #   - requests | ||||
| #   - flask | ||||
| # | ||||
| from __future__ import print_function | ||||
| import json, requests, tarfile, argparse, os, errno | ||||
| import time | ||||
| from urlparse import urljoin | ||||
| from flask import Flask, jsonify, request, abort | ||||
| 
 | ||||
| app = Flask(__name__) | ||||
| 
 | ||||
| arg_jenkins_url, arg_extract_path, arg_should_clean, arg_symlink, arg_config_location = ( | ||||
|     None, None, None, None, None | ||||
| ) | ||||
| arg_jenkins_url = None | ||||
| arg_extract_path = None | ||||
| arg_bundles_path = None | ||||
| arg_should_clean = None | ||||
| arg_symlink = None | ||||
| arg_config_location = None | ||||
| 
 | ||||
| class DeployException(Exception): | ||||
|     pass | ||||
| 
 | ||||
| def download_file(url): | ||||
|     local_filename = url.split('/')[-1] | ||||
|  | @ -57,6 +76,9 @@ def on_receive_jenkins_poke(): | |||
|         abort(400, "Missing or bad build number") | ||||
|         return | ||||
| 
 | ||||
|     return fetch_jenkins_build(job_name, build_num) | ||||
| 
 | ||||
| def fetch_jenkins_build(job_name, build_num): | ||||
|     artifact_url = urljoin( | ||||
|         arg_jenkins_url, "job/%s/%s/api/json" % (job_name, build_num) | ||||
|     ) | ||||
|  | @ -106,7 +128,31 @@ def on_receive_jenkins_poke(): | |||
|         arg_jenkins_url, "job/%s/%s/artifact/%s" % (job_name, build_num, tar_gz_path) | ||||
|     ) | ||||
| 
 | ||||
|     print("Retrieving .tar.gz file: %s" % tar_gz_url) | ||||
|     # we extract into a directory based on the build number. This avoids the | ||||
|     # problem of multiple builds building the same git version and thus having | ||||
|     # the same tarball name. That would lead to two potential problems: | ||||
|     #   (a) sometimes jenkins serves corrupted artifacts; we would replace | ||||
|     #       a good deploy with a bad one | ||||
|     #   (b) we'll be overwriting the live deployment, which means people might | ||||
|     #       see half-written files. | ||||
|     build_dir = os.path.join(arg_extract_path, "%s-#%s" % (job_name, build_num)) | ||||
|     try: | ||||
|         deploy_tarball(tar_gz_url, build_dir) | ||||
|     except DeployException as e: | ||||
|         abort(400, e.message) | ||||
| 
 | ||||
|     return jsonify({}) | ||||
| 
 | ||||
| def deploy_tarball(tar_gz_url, build_dir): | ||||
|     """Download a tarball from jenkins and deploy it as the new version | ||||
|     """ | ||||
|     print("Deploying %s to %s" % (tar_gz_url, build_dir)) | ||||
| 
 | ||||
|     if os.path.exists(build_dir): | ||||
|         raise DeployException( | ||||
|             "Not deploying. We have previously deployed this build." | ||||
|         ) | ||||
|     os.mkdir(build_dir) | ||||
| 
 | ||||
|     # we rely on the fact that flask only serves one request at a time to | ||||
|     # ensure that we do not overwrite a tarball from a concurrent request. | ||||
|  | @ -114,19 +160,6 @@ def on_receive_jenkins_poke(): | |||
|     print("Downloaded file: %s" % filename) | ||||
| 
 | ||||
|     try: | ||||
|         # we extract into a directory based on the build number. This avoids the | ||||
|         # problem of multiple builds building the same git version and thus having | ||||
|         # the same tarball name. That would lead to two potential problems: | ||||
|         #   (a) sometimes jenkins serves corrupted artifacts; we would replace | ||||
|         #       a good deploy with a bad one | ||||
|         #   (b) we'll be overwriting the live deployment, which means people might | ||||
|         #       see half-written files. | ||||
|         build_dir = os.path.join(arg_extract_path, "%s-#%s" % (job_name, build_num)) | ||||
|         if os.path.exists(build_dir): | ||||
|             abort(400, "Not deploying. We have previously deployed this build.") | ||||
|             return | ||||
|         os.mkdir(build_dir) | ||||
| 
 | ||||
|         untar_to(filename, build_dir) | ||||
|         print("Extracted to: %s" % build_dir) | ||||
|     finally: | ||||
|  | @ -139,9 +172,47 @@ def on_receive_jenkins_poke(): | |||
|     if arg_config_location: | ||||
|         create_symlink(source=arg_config_location, linkname=os.path.join(extracted_dir, 'config.json')) | ||||
| 
 | ||||
|     if arg_bundles_path: | ||||
|         extracted_bundles = os.path.join(extracted_dir, 'bundles') | ||||
|         move_bundles(source=extracted_bundles, dest=arg_bundles_path) | ||||
| 
 | ||||
|         # replace the (hopefully now empty) extracted_bundles dir with a | ||||
|         # symlink to the common dir. | ||||
|         relpath = os.path.relpath(arg_bundles_path, extracted_dir) | ||||
|         os.rmdir(extracted_bundles) | ||||
|         print ("Symlink %s -> %s" % (extracted_bundles, relpath)) | ||||
|         os.symlink(relpath, extracted_bundles) | ||||
| 
 | ||||
|     create_symlink(source=extracted_dir, linkname=arg_symlink) | ||||
| 
 | ||||
|     return jsonify({}) | ||||
| def move_bundles(source, dest): | ||||
|     """Move the contents of the 'bundles' directory to a common dir | ||||
| 
 | ||||
|     We check that we will not be overwriting anything before we proceed. | ||||
| 
 | ||||
|     Args: | ||||
|         source (str): path to 'bundles' within the extracted tarball | ||||
|         dest (str): target common directory | ||||
|     """ | ||||
| 
 | ||||
|     if not os.path.isdir(dest): | ||||
|         os.mkdir(dest) | ||||
| 
 | ||||
|     # build a map from source to destination, checking for non-existence as we go. | ||||
|     renames = {} | ||||
|     for f in os.listdir(source): | ||||
|         dst = os.path.join(dest, f) | ||||
|         if os.path.exists(dst): | ||||
|             raise DeployException( | ||||
|                 "Not deploying. The bundle includes '%s' which we have previously deployed." | ||||
|                 % f | ||||
|             ) | ||||
|         renames[os.path.join(source, f)] = dst | ||||
| 
 | ||||
|     for (src, dst) in renames.iteritems(): | ||||
|         print ("Move %s -> %s" % (src, dst)) | ||||
|         os.rename(src, dst) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == "__main__": | ||||
|     parser = argparse.ArgumentParser("Runs a Vector redeployment server.") | ||||
|  | @ -161,6 +232,13 @@ if __name__ == "__main__": | |||
|             "The location to extract .tar.gz files to." | ||||
|         ) | ||||
|     ) | ||||
|     parser.add_argument( | ||||
|         "-b", "--bundles-dir", dest="bundles_dir", help=( | ||||
|             "A directory to move the contents of the 'bundles' directory to. A \ | ||||
|             symlink to the bundles directory will also be written inside the \ | ||||
|             extracted tarball. Example: './bundles'." | ||||
|         ) | ||||
|     ) | ||||
|     parser.add_argument( | ||||
|         "-c", "--clean", dest="clean", action="store_true", default=False, help=( | ||||
|             "Remove .tar.gz files after they have been downloaded and extracted." | ||||
|  | @ -179,18 +257,34 @@ if __name__ == "__main__": | |||
|             To this location." | ||||
|         ) | ||||
|     ) | ||||
|     parser.add_argument( | ||||
|         "--test", dest="tarball_uri", help=( | ||||
|             "Don't start an HTTP listener. Instead download a build from Jenkins \ | ||||
|             immediately." | ||||
|         ), | ||||
|     ) | ||||
| 
 | ||||
|     args = parser.parse_args() | ||||
|     if args.jenkins.endswith("/"): # important for urljoin | ||||
|         arg_jenkins_url = args.jenkins | ||||
|     else: | ||||
|         arg_jenkins_url = args.jenkins + "/" | ||||
|     arg_extract_path = args.extract | ||||
|     arg_bundles_path = args.bundles_dir | ||||
|     arg_should_clean = args.clean | ||||
|     arg_symlink = args.symlink | ||||
|     arg_config_location = args.config | ||||
|     print( | ||||
|         "Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s. Config location: %s" % | ||||
|         (args.port, arg_extract_path, | ||||
|             " (clean after)" if arg_should_clean else "", arg_symlink, arg_jenkins_url, arg_config_location) | ||||
|     ) | ||||
|     app.run(host="0.0.0.0", port=args.port, debug=True) | ||||
| 
 | ||||
|     if not os.path.isdir(arg_extract_path): | ||||
|         os.mkdir(arg_extract_path) | ||||
| 
 | ||||
|     if args.tarball_uri is not None: | ||||
|         build_dir = os.path.join(arg_extract_path, "test-%i" % (time.time())) | ||||
|         deploy_tarball(args.tarball_uri, build_dir) | ||||
|     else: | ||||
|         print( | ||||
|             "Listening on port %s. Extracting to %s%s. Symlinking to %s. Jenkins URL: %s. Config location: %s" % | ||||
|             (args.port, arg_extract_path, | ||||
|              " (clean after)" if arg_should_clean else "", arg_symlink, arg_jenkins_url, arg_config_location) | ||||
|         ) | ||||
|         app.run(host="0.0.0.0", port=args.port, debug=True) | ||||
|  |  | |||
|  | @ -44,7 +44,7 @@ input[type=text].mx_DirectorySearchBox_input:focus { | |||
|     padding-right: 10px; | ||||
|     background-color: $plinth-bg-color; | ||||
|     border-radius: 3px; | ||||
|     background-image: url('img/icon-return.svg'); | ||||
|     background-image: url('../../img/icon-return.svg'); | ||||
|     background-position: 8px 70%; | ||||
|     background-repeat: no-repeat; | ||||
|     text-indent: 18px; | ||||
|  | @ -61,7 +61,7 @@ input[type=text].mx_DirectorySearchBox_input:focus { | |||
| .mx_DirectorySearchBox_clear { | ||||
|     display: inline-block; | ||||
|     vertical-align: middle; | ||||
|     background: url('img/icon_context_delete.svg'); | ||||
|     background: url('../../img/icon_context_delete.svg'); | ||||
|     background-position: 0 50%; | ||||
|     background-repeat: no-repeat; | ||||
|     width: 15px; | ||||
|  |  | |||
|  | @ -65,7 +65,7 @@ limitations under the License. | |||
|     position: absolute; | ||||
|     content: ""; | ||||
|     border-radius: 40px; | ||||
|     background-image: url("img/icons_ellipsis.svg"); | ||||
|     background-image: url("../../img/icons_ellipsis.svg"); | ||||
|     background-size: 25px; | ||||
|     width: 24px; | ||||
|     height: 24px; | ||||
|  |  | |||
|  | @ -3,44 +3,46 @@ | |||
|  * Includes extended Latin, Greek, Cyrillic and Vietnamese character sets | ||||
|  */ | ||||
| 
 | ||||
| /* the 'src' links are relative to the bundle.css, which is in a subdirectory. | ||||
|  */ | ||||
| @font-face { | ||||
|     font-family: 'Open Sans'; | ||||
|     src: url('fonts/Open_Sans/OpenSans-Regular.ttf') format('truetype'); | ||||
|     src: url('../../fonts/Open_Sans/OpenSans-Regular.ttf') format('truetype'); | ||||
|     font-weight: 400; | ||||
|     font-style: normal; | ||||
| } | ||||
| 
 | ||||
| @font-face { | ||||
|     font-family: 'Open Sans'; | ||||
|     src: url('fonts/Open_Sans/OpenSans-Italic.ttf') format('truetype'); | ||||
|     src: url('../../fonts/Open_Sans/OpenSans-Italic.ttf') format('truetype'); | ||||
|     font-weight: 400; | ||||
|     font-style: italic; | ||||
| } | ||||
| 
 | ||||
| @font-face { | ||||
|     font-family: 'Open Sans'; | ||||
|     src: url('fonts/Open_Sans/OpenSans-Semibold.ttf') format('truetype'); | ||||
|     src: url('../../fonts/Open_Sans/OpenSans-Semibold.ttf') format('truetype'); | ||||
|     font-weight: 600; | ||||
|     font-style: normal; | ||||
| } | ||||
| 
 | ||||
| @font-face { | ||||
|     font-family: 'Open Sans'; | ||||
|     src: url('fonts/Open_Sans/OpenSans-SemiboldItalic.ttf') format('truetype'); | ||||
|     src: url('../../fonts/Open_Sans/OpenSans-SemiboldItalic.ttf') format('truetype'); | ||||
|     font-weight: 600; | ||||
|     font-style: italic; | ||||
| } | ||||
| 
 | ||||
| @font-face { | ||||
|     font-family: 'Open Sans'; | ||||
|     src: url('fonts/Open_Sans/OpenSans-Bold.ttf') format('truetype'); | ||||
|     src: url('../../fonts/Open_Sans/OpenSans-Bold.ttf') format('truetype'); | ||||
|     font-weight: 700; | ||||
|     font-style: normal; | ||||
| } | ||||
| 
 | ||||
| @font-face { | ||||
|     font-family: 'Open Sans'; | ||||
|     src: url('fonts/Open_Sans/OpenSans-BoldItalic.ttf') format('truetype'); | ||||
|     src: url('../../fonts/Open_Sans/OpenSans-BoldItalic.ttf') format('truetype'); | ||||
|     font-weight: 700; | ||||
|     font-style: italic; | ||||
| } | ||||
|  | @ -52,14 +54,14 @@ | |||
| 
 | ||||
| @font-face { | ||||
|     font-family: 'Fira Mono'; | ||||
|     src: url('fonts/Fira_Mono/FiraMono-Regular.ttf') format('truetype'); | ||||
|     src: url('../../fonts/Fira_Mono/FiraMono-Regular.ttf') format('truetype'); | ||||
|     font-weight: 400; | ||||
|     font-style: normal; | ||||
| } | ||||
| 
 | ||||
| @font-face { | ||||
|     font-family: 'Fira Mono'; | ||||
|     src: url('fonts/Fira_Mono/FiraMono-Bold.ttf') format('truetype'); | ||||
|     src: url('../../fonts/Fira_Mono/FiraMono-Bold.ttf') format('truetype'); | ||||
|     font-weight: 700; | ||||
|     font-style: normal; | ||||
| } | ||||
|  |  | |||
|  | @ -50,7 +50,7 @@ limitations under the License. | |||
|     max-height: 100%; | ||||
|     /* object-fit hack needed for Chrome due to Chrome not re-laying-out until you refresh */ | ||||
|     object-fit: contain; | ||||
|     /* background-image: url('img/trans.png'); */ | ||||
|     /* background-image: url('../../img/trans.png'); */ | ||||
|     pointer-events: all; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -45,7 +45,17 @@ module.exports = { | |||
|     }, | ||||
|     output: { | ||||
|         path: path.join(__dirname, "webapp"), | ||||
|         filename: "[name].[chunkhash].js", | ||||
| 
 | ||||
|         // the generated js (and CSS, from the ExtractTextPlugin) are put in a
 | ||||
|         // unique subdirectory for the build. There will only be one such
 | ||||
|         // 'bundle' directory in the generated tarball; however, hosting
 | ||||
|         // servers can collect 'bundles' from multiple versions into one
 | ||||
|         // directory and symlink it into place - this allows users who loaded
 | ||||
|         // an older version of the application to continue to access webpack
 | ||||
|         // chunks even after the app is redeployed.
 | ||||
|         //
 | ||||
|         filename: "bundles/[hash]/[name].js", | ||||
|         chunkFilename: "bundles/[hash]/[name].js", | ||||
|         devtoolModuleFilenameTemplate: function(info) { | ||||
|             // Reading input source maps gives only relative paths here for
 | ||||
|             // everything. Until I figure out how to fix this, this is a
 | ||||
|  | @ -84,7 +94,7 @@ module.exports = { | |||
|         }), | ||||
| 
 | ||||
|         new ExtractTextPlugin( | ||||
|             "[name].[contenthash].css", | ||||
|             "bundles/[hash]/[name].css", | ||||
|             { | ||||
|                 allChunks: true | ||||
|             } | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue
	
	 Matthew Hodgson
						Matthew Hodgson