diff --git a/Makefile b/Makefile index ebd3973ad..d56145618 100644 --- a/Makefile +++ b/Makefile @@ -44,7 +44,7 @@ client/build/app.js: client/app/scripts/* mkdir -p client/build docker run -ti -v $(shell pwd)/client/app:/home/weave/app \ -v $(shell pwd)/client/build:/home/weave/build \ - $(SCOPE_UI_BUILD_IMAGE) gulp build --release + $(SCOPE_UI_BUILD_IMAGE) npm run build client-test: client/test/* docker run -ti -v $(shell pwd)/client/app:/home/weave/app \ @@ -56,18 +56,18 @@ client-lint: -v $(shell pwd)/client/test:/home/weave/test \ $(SCOPE_UI_BUILD_IMAGE) npm run lint -client-sync: +client-start: docker run -ti --net=host -v $(shell pwd)/client/app:/home/weave/app \ -v $(shell pwd)/client/build:/home/weave/build \ - $(SCOPE_UI_BUILD_IMAGE) gulp sync + $(SCOPE_UI_BUILD_IMAGE) npm start -$(SCOPE_UI_BUILD_EXPORT): client/Dockerfile client/gulpfile.js client/package.json client/webpack.config.js client/.eslintrc +$(SCOPE_UI_BUILD_EXPORT): client/Dockerfile client/package.json client/webpack.local.config.js client/webpack.production.config.js client/server.js client/.eslintrc docker build -t $(SCOPE_UI_BUILD_IMAGE) client docker save $(SCOPE_UI_BUILD_IMAGE):latest > $@ clean: go clean ./... - rm -rf $(SCOPE_EXPORT) $(SCOPE_UI_BUILD_EXPORT) $(APP_EXE) $(PROBE_EXE) client/build + rm -rf $(SCOPE_EXPORT) $(SCOPE_UI_BUILD_EXPORT) $(APP_EXE) $(PROBE_EXE) client/build/app.js deps: go get \ diff --git a/circle.yml b/circle.yml index 28969159f..f1922e685 100644 --- a/circle.yml +++ b/circle.yml @@ -35,7 +35,7 @@ dependencies: - make deps - mkdir -p $(dirname $SRCDIR) - cp -r $(pwd)/ $SRCDIR - - cd $SRCDIR/client; $TOOLS/rebuild-image weaveworks/scope-ui-build . Dockerfile gulpfile.js package.json webpack.config.js .eslintrc + - cd $SRCDIR/client; $TOOLS/rebuild-image weaveworks/scope-ui-build . Dockerfile package.json webpack.production.config.js .eslintrc test: override: diff --git a/client/.gitignore b/client/.gitignore index dd87e2d73..a8187ae69 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -1,2 +1,3 @@ node_modules -build +build/app.js +build/*[woff2?|ttf|eot|svg] diff --git a/client/Dockerfile b/client/Dockerfile index 90a805316..b757b42cf 100644 --- a/client/Dockerfile +++ b/client/Dockerfile @@ -1,6 +1,5 @@ FROM node:0.10 WORKDIR /home/weave -RUN npm install -g gulp COPY package.json /home/weave/ RUN npm install -COPY gulpfile.js webpack.config.js .eslintrc /home/weave/ +COPY webpack.local.config.js webpack.production.config.js server.js .eslintrc /home/weave/ diff --git a/client/README.md b/client/README.md index 2f0a3f2b6..390cd728c 100644 --- a/client/README.md +++ b/client/README.md @@ -3,15 +3,15 @@ ## Getting Started - Setup: `npm install` -- Build: `gulp build --release`, output will be in `build/` -- Develop: `gulp sync` and then open `http://localhost:4042/` +- Build: `npm run build`, output will be in `build/` +- Develop: `npm start` and then open `http://localhost:4042/` To see a topology, `../app/app` needs to be running, as well as a probe. ## Coding This directory has a `.eslintrc`, make sure your editor supports linter hints. -To run a linter, you also run `gulp lint`. +To run a linter, you also run `npm run lint`. ## Logging diff --git a/client/app/.htaccess b/client/app/.htaccess deleted file mode 100644 index ca346584c..000000000 --- a/client/app/.htaccess +++ /dev/null @@ -1,663 +0,0 @@ -# Apache Server Configs v2.2.0 | MIT License -# https://github.com/h5bp/server-configs-apache - -# (!) Using `.htaccess` files slows down Apache, therefore, if you have access -# to the main server config file (usually called `httpd.conf`), you should add -# this logic there: http://httpd.apache.org/docs/current/howto/htaccess.html. - -# ############################################################################## -# # CROSS-ORIGIN RESOURCE SHARING (CORS) # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Cross-domain AJAX requests | -# ------------------------------------------------------------------------------ - -# Allow cross-origin AJAX requests. -# http://code.google.com/p/html5security/wiki/CrossOriginRequestSecurity -# http://enable-cors.org/ - -# -# Header set Access-Control-Allow-Origin "*" -# - -# ------------------------------------------------------------------------------ -# | CORS-enabled images | -# ------------------------------------------------------------------------------ - -# Send the CORS header for images when browsers request it. -# https://developer.mozilla.org/en-US/docs/HTML/CORS_Enabled_Image -# http://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html -# http://hacks.mozilla.org/2011/11/using-cors-to-load-webgl-textures-from-cross-domain-images/ - - - - - SetEnvIf Origin ":" IS_CORS - Header set Access-Control-Allow-Origin "*" env=IS_CORS - - - - -# ------------------------------------------------------------------------------ -# | Web fonts access | -# ------------------------------------------------------------------------------ - -# Allow access to web fonts from all domains. - - - - Header set Access-Control-Allow-Origin "*" - - - - -# ############################################################################## -# # ERRORS # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | 404 error prevention for non-existing redirected folders | -# ------------------------------------------------------------------------------ - -# Prevent Apache from returning a 404 error as the result of a rewrite -# when the directory with the same name does not exist. -# http://httpd.apache.org/docs/current/content-negotiation.html#multiviews -# http://www.webmasterworld.com/apache/3808792.htm - -Options -MultiViews - -# ------------------------------------------------------------------------------ -# | Custom error messages / pages | -# ------------------------------------------------------------------------------ - -# Customize what Apache returns to the client in case of an error. -# http://httpd.apache.org/docs/current/mod/core.html#errordocument - -ErrorDocument 404 /404.html - - -# ############################################################################## -# # INTERNET EXPLORER # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Better website experience | -# ------------------------------------------------------------------------------ - -# Force Internet Explorer to render pages in the highest available mode -# in the various cases when it may not. -# http://hsivonen.iki.fi/doctype/ie-mode.pdf - - - Header set X-UA-Compatible "IE=edge" - # `mod_headers` cannot match based on the content-type, however, this - # header should be send only for HTML pages and not for the other resources - - Header unset X-UA-Compatible - - - -# ------------------------------------------------------------------------------ -# | Cookie setting from iframes | -# ------------------------------------------------------------------------------ - -# Allow cookies to be set from iframes in Internet Explorer. -# http://msdn.microsoft.com/en-us/library/ms537343.aspx -# http://www.w3.org/TR/2000/CR-P3P-20001215/ - -# -# Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\"" -# - - -# ############################################################################## -# # MIME TYPES AND ENCODING # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Proper MIME types for all files | -# ------------------------------------------------------------------------------ - - - - # Audio - AddType audio/mp4 m4a f4a f4b - AddType audio/ogg oga ogg opus - - # Data interchange - AddType application/json json map - AddType application/ld+json jsonld - - # JavaScript - # Normalize to standard type. - # http://tools.ietf.org/html/rfc4329#section-7.2 - AddType application/javascript js - - # Video - AddType video/mp4 f4v f4p m4v mp4 - AddType video/ogg ogv - AddType video/webm webm - AddType video/x-flv flv - - # Web fonts - AddType application/font-woff woff - AddType application/vnd.ms-fontobject eot - - # Browsers usually ignore the font MIME types and simply sniff the bytes - # to figure out the font type. - # http://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern - - # Chrome however, shows a warning if any other MIME types are used for - # the following fonts. - - AddType application/x-font-ttf ttc ttf - AddType font/opentype otf - - # Make SVGZ fonts work on the iPad. - # https://twitter.com/FontSquirrel/status/14855840545 - AddType image/svg+xml svgz - AddEncoding gzip svgz - - # Other - AddType application/octet-stream safariextz - AddType application/x-chrome-extension crx - AddType application/x-opera-extension oex - AddType application/x-web-app-manifest+json webapp - AddType application/x-xpinstall xpi - AddType application/xml atom rdf rss xml - AddType image/webp webp - AddType image/x-icon cur - AddType text/cache-manifest appcache manifest - AddType text/vtt vtt - AddType text/x-component htc - AddType text/x-vcard vcf - - - -# ------------------------------------------------------------------------------ -# | UTF-8 encoding | -# ------------------------------------------------------------------------------ - -# Use UTF-8 encoding for anything served as `text/html` or `text/plain`. -AddDefaultCharset utf-8 - -# Force UTF-8 for certain file formats. - - AddCharset utf-8 .atom .css .js .json .jsonld .rss .vtt .webapp .xml - - - -# ############################################################################## -# # URL REWRITES # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Rewrite engine | -# ------------------------------------------------------------------------------ - -# Turn on the rewrite engine and enable the `FollowSymLinks` option (this is -# necessary in order for the following directives to work). - -# If your web host doesn't allow the `FollowSymlinks` option, you may need to -# comment it out and use `Options +SymLinksIfOwnerMatch`, but be aware of the -# performance impact. -# http://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks - -# Also, some cloud hosting services require `RewriteBase` to be set. -# http://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-mod-rewrite-not-working-on-my-site - - - Options +FollowSymlinks - # Options +SymLinksIfOwnerMatch - RewriteEngine On - # RewriteBase / - - -# ------------------------------------------------------------------------------ -# | Suppressing / Forcing the `www.` at the beginning of URLs | -# ------------------------------------------------------------------------------ - -# The same content should never be available under two different URLs, -# especially not with and without `www.` at the beginning. This can cause -# SEO problems (duplicate content), and therefore, you should choose one -# of the alternatives and redirect the other one. - -# By default `Option 1` (no `www.`) is activated. -# http://no-www.org/faq.php?q=class_b - -# If you would prefer to use `Option 2`, just comment out all the lines -# from `Option 1` and uncomment the ones from `Option 2`. - -# IMPORTANT: NEVER USE BOTH RULES AT THE SAME TIME! - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Option 1: rewrite www.example.com → example.com - - - RewriteCond %{HTTPS} !=on - RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC] - RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L] - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Option 2: rewrite example.com → www.example.com - -# Be aware that the following might not be a good idea if you use "real" -# subdomains for certain parts of your website. - -# -# RewriteCond %{HTTPS} !=on -# RewriteCond %{HTTP_HOST} !^www\. [NC] -# RewriteCond %{SERVER_ADDR} !=127.0.0.1 -# RewriteCond %{SERVER_ADDR} !=::1 -# RewriteRule ^ http://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L] -# - - -# ############################################################################## -# # SECURITY # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Clickjacking | -# ------------------------------------------------------------------------------ - -# Protect website against clickjacking. - -# The example below sends the `X-Frame-Options` response header with the value -# `DENY`, informing browsers not to display the web page content in any frame. - -# This might not be the best setting for everyone. You should read about the -# other two possible values for `X-Frame-Options`: `SAMEORIGIN` & `ALLOW-FROM`. -# http://tools.ietf.org/html/rfc7034#section-2.1 - -# Keep in mind that while you could send the `X-Frame-Options` header for all -# of your site’s pages, this has the potential downside that it forbids even -# non-malicious framing of your content (e.g.: when users visit your site using -# a Google Image Search results page). - -# Nonetheless, you should ensure that you send the `X-Frame-Options` header for -# all pages that allow a user to make a state changing operation (e.g: pages -# that contain one-click purchase links, checkout or bank-transfer confirmation -# pages, pages that make permanent configuration changes, etc.). - -# Sending the `X-Frame-Options` header can also protect your website against -# more than just clickjacking attacks: https://cure53.de/xfo-clickjacking.pdf. - -# http://tools.ietf.org/html/rfc7034 -# http://blogs.msdn.com/b/ieinternals/archive/2010/03/30/combating-clickjacking-with-x-frame-options.aspx -# https://www.owasp.org/index.php/Clickjacking - -# -# Header set X-Frame-Options "DENY" -# -# Header unset X-Frame-Options -# -# - -# ------------------------------------------------------------------------------ -# | Content Security Policy (CSP) | -# ------------------------------------------------------------------------------ - -# Mitigate the risk of cross-site scripting and other content-injection attacks. - -# This can be done by setting a `Content Security Policy` which whitelists -# trusted sources of content for your website. - -# The example header below allows ONLY scripts that are loaded from the current -# site's origin (no inline scripts, no CDN, etc). This almost certainly won't -# work as-is for your site! - -# For more details on how to craft a reasonable policy for your site, read: -# http://html5rocks.com/en/tutorials/security/content-security-policy (or the -# specification: http://w3.org/TR/CSP). Also, to make things easier, you can -# use an online CSP header generator such as: http://cspisawesome.com/. - -# -# Header set Content-Security-Policy "script-src 'self'; object-src 'self'" -# -# Header unset Content-Security-Policy -# -# - -# ------------------------------------------------------------------------------ -# | File access | -# ------------------------------------------------------------------------------ - -# Block access to directories without a default document. -# You should leave the following uncommented, as you shouldn't allow anyone to -# surf through every directory on your server (which may includes rather private -# places such as the CMS's directories). - - - Options -Indexes - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Block access to hidden files and directories. -# This includes directories used by version control systems such as Git and SVN. - - - RewriteCond %{SCRIPT_FILENAME} -d [OR] - RewriteCond %{SCRIPT_FILENAME} -f - RewriteRule "(^|/)\." - [F] - - -# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -# Block access to files that can expose sensitive information. - -# By default, block access to backup and source files that may be left by some -# text editors and can pose a security risk when anyone has access to them. -# http://feross.org/cmsploit/ - -# IMPORTANT: Update the `` regular expression from below to include -# any files that might end up on your production server and can expose sensitive -# information about your website. These files may include: configuration files, -# files that contain metadata about the project (e.g.: project dependencies), -# build scripts, etc.. - - - - # Apache < 2.3 - - Order allow,deny - Deny from all - Satisfy All - - - # Apache ≥ 2.3 - - Require all denied - - - - -# ------------------------------------------------------------------------------ -# | Reducing MIME-type security risks | -# ------------------------------------------------------------------------------ - -# Prevent some browsers from MIME-sniffing the response. - -# This reduces exposure to drive-by download attacks and should be enable -# especially if the web server is serving user uploaded content, content -# that could potentially be treated by the browser as executable. - -# http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx -# http://msdn.microsoft.com/en-us/library/ie/gg622941.aspx -# http://mimesniff.spec.whatwg.org/ - -# -# Header set X-Content-Type-Options "nosniff" -# - -# ------------------------------------------------------------------------------ -# | Reflected Cross-Site Scripting (XSS) attacks | -# ------------------------------------------------------------------------------ - -# (1) Try to re-enable the Cross-Site Scripting (XSS) filter built into the -# most recent web browsers. -# -# The filter is usually enabled by default, but in some cases it may be -# disabled by the user. However, in Internet Explorer for example, it can -# be re-enabled just by sending the `X-XSS-Protection` header with the -# value of `1`. -# -# (2) Prevent web browsers from rendering the web page if a potential reflected -# (a.k.a non-persistent) XSS attack is detected by the filter. -# -# By default, if the filter is enabled and browsers detect a reflected -# XSS attack, they will attempt to block the attack by making the smallest -# possible modifications to the returned web page. -# -# Unfortunately, in some browsers (e.g.: Internet Explorer), this default -# behavior may allow the XSS filter to be exploited, thereby, it's better -# to tell browsers to prevent the rendering of the page altogether, instead -# of attempting to modify it. -# -# http://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities -# -# IMPORTANT: Do not rely on the XSS filter to prevent XSS attacks! Ensure that -# you are taking all possible measures to prevent XSS attacks, the most obvious -# being: validating and sanitizing your site's inputs. -# -# http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx -# http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx -# https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29 - -# -# # (1) (2) -# Header set X-XSS-Protection "1; mode=block" -# -# Header unset X-XSS-Protection -# -# - -# ------------------------------------------------------------------------------ -# | Secure Sockets Layer (SSL) | -# ------------------------------------------------------------------------------ - -# Rewrite secure requests properly in order to prevent SSL certificate warnings. -# E.g.: prevent `https://www.example.com` when your certificate only allows -# `https://secure.example.com`. - -# -# RewriteCond %{SERVER_PORT} !^443 -# RewriteRule ^ https://example-domain-please-change-me.com%{REQUEST_URI} [R=301,L] -# - -# ------------------------------------------------------------------------------ -# | HTTP Strict Transport Security (HSTS) | -# ------------------------------------------------------------------------------ - -# Force client-side SSL redirection. - -# If a user types `example.com` in his browser, the above rule will redirect -# him to the secure version of the site. That still leaves a window of -# opportunity (the initial HTTP connection) for an attacker to downgrade or -# redirect the request. - -# The following header ensures that browser will ONLY connect to your server -# via HTTPS, regardless of what the users type in the address bar. - -# http://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-6.1 -# http://www.html5rocks.com/en/tutorials/security/transport-layer-security/ - -# IMPORTANT: Remove the `includeSubDomains` optional directive if the subdomains -# are not using HTTPS. - -# -# Header set Strict-Transport-Security "max-age=16070400; includeSubDomains" -# - -# ------------------------------------------------------------------------------ -# | Server software information | -# ------------------------------------------------------------------------------ - -# Avoid displaying the exact Apache version number, the description of the -# generic OS-type and the information about Apache's compiled-in modules. - -# ADD THIS DIRECTIVE IN THE `httpd.conf` AS IT WILL NOT WORK IN THE `.htaccess`! - -# ServerTokens Prod - - -# ############################################################################## -# # WEB PERFORMANCE # -# ############################################################################## - -# ------------------------------------------------------------------------------ -# | Compression | -# ------------------------------------------------------------------------------ - - - - # Force compression for mangled headers. - # http://developer.yahoo.com/blogs/ydn/posts/2010/12/pushing-beyond-gzipping - - - SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding - RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding - - - - # Compress all output labeled with one of the following MIME-types - # (for Apache versions below 2.3.7, you don't need to enable `mod_filter` - # and can remove the `` and `` lines - # as `AddOutputFilterByType` is still in the core directives). - - AddOutputFilterByType DEFLATE application/atom+xml \ - application/javascript \ - application/json \ - application/ld+json \ - application/rss+xml \ - application/vnd.ms-fontobject \ - application/x-font-ttf \ - application/x-web-app-manifest+json \ - application/xhtml+xml \ - application/xml \ - font/opentype \ - image/svg+xml \ - image/x-icon \ - text/css \ - text/html \ - text/plain \ - text/x-component \ - text/xml - - - - -# ------------------------------------------------------------------------------ -# | Content transformations | -# ------------------------------------------------------------------------------ - -# Prevent mobile network providers from modifying the website's content. -# http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.9.5. - -# -# Header set Cache-Control "no-transform" -# - -# ------------------------------------------------------------------------------ -# | ETags | -# ------------------------------------------------------------------------------ - -# Remove `ETags` as resources are sent with far-future expires headers. -# http://developer.yahoo.com/performance/rules.html#etags. - -# `FileETag None` doesn't work in all cases. - - Header unset ETag - - -FileETag None - -# ------------------------------------------------------------------------------ -# | Expires headers | -# ------------------------------------------------------------------------------ - -# The following expires headers are set pretty far in the future. If you -# don't control versioning with filename-based cache busting, consider -# lowering the cache time for resources such as style sheets and JavaScript -# files to something like one week. - - - - ExpiresActive on - ExpiresDefault "access plus 1 month" - - # CSS - ExpiresByType text/css "access plus 1 year" - - # Data interchange - ExpiresByType application/json "access plus 0 seconds" - ExpiresByType application/ld+json "access plus 0 seconds" - ExpiresByType application/xml "access plus 0 seconds" - ExpiresByType text/xml "access plus 0 seconds" - - # Favicon (cannot be renamed!) and cursor images - ExpiresByType image/x-icon "access plus 1 week" - - # HTML components (HTCs) - ExpiresByType text/x-component "access plus 1 month" - - # HTML - ExpiresByType text/html "access plus 0 seconds" - - # JavaScript - ExpiresByType application/javascript "access plus 1 year" - - # Manifest files - ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds" - ExpiresByType text/cache-manifest "access plus 0 seconds" - - # Media - ExpiresByType audio/ogg "access plus 1 month" - ExpiresByType image/gif "access plus 1 month" - ExpiresByType image/jpeg "access plus 1 month" - ExpiresByType image/png "access plus 1 month" - ExpiresByType video/mp4 "access plus 1 month" - ExpiresByType video/ogg "access plus 1 month" - ExpiresByType video/webm "access plus 1 month" - - # Web feeds - ExpiresByType application/atom+xml "access plus 1 hour" - ExpiresByType application/rss+xml "access plus 1 hour" - - # Web fonts - ExpiresByType application/font-woff "access plus 1 month" - ExpiresByType application/vnd.ms-fontobject "access plus 1 month" - ExpiresByType application/x-font-ttf "access plus 1 month" - ExpiresByType font/opentype "access plus 1 month" - ExpiresByType image/svg+xml "access plus 1 month" - - - -# ------------------------------------------------------------------------------ -# | Filename-based cache busting | -# ------------------------------------------------------------------------------ - -# If you're not using a build process to manage your filename version revving, -# you might want to consider enabling the following directives to route all -# requests such as `/css/style.12345.css` to `/css/style.css`. - -# To understand why this is important and a better idea than `*.css?v231`, read: -# http://stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring - -# -# RewriteCond %{REQUEST_FILENAME} !-f -# RewriteRule ^(.+)\.(\d+)\.(js|css|png|jpe?g|gif)$ $1.$3 [L] -# - -# ------------------------------------------------------------------------------ -# | File concatenation | -# ------------------------------------------------------------------------------ - -# Allow concatenation from within specific style sheets and JavaScript files. - -# e.g.: -# -# If you have the following content in a file -# -# -# -# -# Apache will replace it with the content from the specified files. - -# -# -# Options +Includes -# AddOutputFilterByType INCLUDES application/javascript application/json -# SetOutputFilter INCLUDES -# -# -# Options +Includes -# AddOutputFilterByType INCLUDES text/css -# SetOutputFilter INCLUDES -# -# diff --git a/client/app/404.html b/client/app/404.html deleted file mode 100644 index fdace4ab1..000000000 --- a/client/app/404.html +++ /dev/null @@ -1,157 +0,0 @@ - - - - - Page Not Found :( - - - -
-

Not found :(

-

Sorry, but the page you were trying to view does not exist.

-

It looks like this was the result of either:

- - - -
- - diff --git a/client/app/images/logo.svg b/client/app/images/logo.svg deleted file mode 100644 index 2e907ab72..000000000 --- a/client/app/images/logo.svg +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - diff --git a/client/app/robots.txt b/client/app/robots.txt deleted file mode 100644 index ee2cc216a..000000000 --- a/client/app/robots.txt +++ /dev/null @@ -1,3 +0,0 @@ -# robotstxt.org/ - -User-agent: * diff --git a/client/app/scripts/local.js b/client/app/scripts/local.js new file mode 100644 index 000000000..1345c0bd1 --- /dev/null +++ b/client/app/scripts/local.js @@ -0,0 +1,7 @@ +// This file is an entrypoint for development, +// see main.js for the real entrypoint + +// Inject websocket url to dev backend +window.WS_URL = 'ws://' + location.hostname + ':4040'; + +require('./main'); diff --git a/client/app/favicon.ico b/client/build/favicon.ico similarity index 100% rename from client/app/favicon.ico rename to client/build/favicon.ico diff --git a/client/app/index.html b/client/build/index.html similarity index 82% rename from client/app/index.html rename to client/build/index.html index 28d450b62..17d2608ee 100644 --- a/client/app/index.html +++ b/client/build/index.html @@ -14,10 +14,6 @@
- - - - diff --git a/client/gulpfile.js b/client/gulpfile.js deleted file mode 100644 index 202bc99ef..000000000 --- a/client/gulpfile.js +++ /dev/null @@ -1,165 +0,0 @@ -/* - * Gulpfile based on https://github.com/kriasoft/react-starter-kit - */ - -'use strict'; - -var gulp = require('gulp'); -var $ = require('gulp-load-plugins')(); -var del = require('del'); -var path = require('path'); -var runSequence = require('run-sequence'); -var webpack = require('webpack'); -var argv = require('minimist')(process.argv.slice(2)); - -var watch = false; -var browserSync; - -// The default task -gulp.task('default', ['build']); - -// Clean output directory -gulp.task('clean', del.bind( - null, ['.tmp', 'build/*'], {dot: true} -)); - -// Favicon -gulp.task('favicon', function() { - return gulp.src(['app/favicon.ico']) - .pipe(gulp.dest('build')); -}); - - -// Static files -gulp.task('html', function() { - var release = !!argv.release; - - return gulp.src('app/*.html') - .pipe($.changed('build')) - .pipe($.if(release, $.preprocess())) - .pipe(gulp.dest('build')) - .pipe($.size({title: 'html'})); -}); - -// Bundle -gulp.task('bundle', function(cb) { - var started = false; - var config = require('./webpack.config.js'); - var bundler = webpack(config); - var verbose = !!argv.verbose; - - function bundle(err, stats) { - if (err) { - throw new $.util.PluginError('webpack', err); - } - - console.log(stats.toString({ - colors: $.util.colors.supportsColor, - hash: verbose, - version: verbose, - timings: verbose, - chunks: verbose, - chunkModules: verbose, - cached: verbose, - cachedAssets: verbose - })); - - if (!started) { - started = true; - return cb(); - } - } - - if (watch) { - bundler.watch(200, bundle); - } else { - bundler.run(bundle); - } -}); - -// Build the app from source code -gulp.task('build', ['clean'], function(cb) { - runSequence(['html', 'favicon', 'bundle'], cb); -}); - -// Build and start watching for modifications -gulp.task('build:watch', function(cb) { - watch = true; - runSequence('build', function() { - gulp.watch('app/*.html', ['html']); - cb(); - }); -}); - -// Launch a Node.js/Express server -gulp.task('serve', ['build:watch'], function() { - $.connect.server({ - root: ['build'], - port: 4041, - middleware: function() { - return [(function() { - var url = require('url'); - var proxy = require('proxy-middleware'); - var options = url.parse('http://localhost:4040/api'); - options.route = '/api'; - return proxy(options); - })()]; - }, - livereload: false - }); -}); - -// Launch BrowserSync development server -gulp.task('sync', ['serve'], function(cb) { - browserSync = require('browser-sync'); - - browserSync({ - logPrefix: 'RSK', - // Stop the browser from automatically opening - open: false, - notify: false, - // Run as an https by setting 'https: true' - // Note: this uses an unsigned certificate which on first access - // will present a certificate warning in the browser. - https: false, - // Will not attempt to determine your network status, assumes you're OFFLINE - online: false, - port: 4042, - // Informs browser-sync to proxy our Express app which would run - // at the following location - proxy: 'localhost:4041', - // dont refresh immediately after successive changes - reloadDebounce: 2000, - // browserSync webapp - ui: { - port: 4043 - } - }, cb); - - process.on('exit', function() { - browserSync.exit(); - }); - - gulp.watch('build/**/*.*', browserSync.reload); - - // FIX this part to only reload styles parts that changed - // gulp.watch(['build/**/*.*'].concat( - // src.server.map(function(file) { return '!' + file; }) - // ), function(file) { - // browserSync.reload(path.relative(__dirname, file.path)); - // }); -}); - -// Lint -gulp.task('lint', function() { - return gulp.src(['app/**/*.js']) - // eslint() attaches the lint output to the eslint property - // of the file object so it can be used by other modules. - .pipe($.eslint()) - // eslint.format() outputs the lint results to the console. - // Alternatively use eslint.formatEach() (see Docs). - .pipe($.eslint.format()) - // To have the process exit with an error code (1) on - // lint error, return the stream and pipe to failOnError last. - .pipe($.eslint.failOnError()); -}); diff --git a/client/package.json b/client/package.json index 1c0b695c6..f9268e64e 100644 --- a/client/package.json +++ b/client/package.json @@ -11,6 +11,7 @@ "debug": "^2.2.0", "flux": "^2.0.3", "font-awesome": "^4.3.0", + "font-awesome-webpack": "0.0.3", "keymirror": "^0.1.1", "lodash": "~3.9.3", "material-ui": "~0.7.5", @@ -28,27 +29,14 @@ "babel-core": "^5.4.7", "babel-eslint": "^3.1.9", "babel-loader": "^5.1.3", - "babelify": "^6.1.2", - "browser-sync": "^2.7.6", "css-loader": "^0.14.4", - "del": "^1.2.0", "eslint": "^0.21.2", "eslint-loader": "^0.11.2", "eslint-plugin-jasmine": "^1.0.0", "eslint-plugin-react": "^2.3.0", + "express": "^4.13.3", + "express-http-proxy": "^0.6.0", "file-loader": "^0.8.4", - "font-awesome-webpack": "0.0.3", - "gulp": "^3.8.11", - "gulp-autoprefixer": "^2.3.0", - "gulp-changed": "^1.2.1", - "gulp-connect": "^2.2.0", - "gulp-eslint": "^0.12.0", - "gulp-filter": "^2.0.2", - "gulp-if": "^1.2.5", - "gulp-load-plugins": "^0.10.0", - "gulp-preprocess": "^1.2.0", - "gulp-size": "^1.2.1", - "gulp-util": "^3.0.4", "istanbul-instrumenter-loader": "^0.1.3", "jasmine-core": "^2.3.4", "karma": "^0.13.3", @@ -59,24 +47,26 @@ "karma-webpack": "^1.7.0", "less": "^2.5.1", "less-loader": "^2.2.0", - "minimist": "^1.1.1", - "node-libs-browser": "^0.5.2", "phantomjs": "^1.9.18", "postcss-loader": "^0.4.3", - "proxy-middleware": "^0.12.0", + "proxy-middleware": "^0.13.1", + "react-hot-loader": "^1.2.8", "react-tools": "^0.13.3", - "reactify": "^1.1.1", - "run-sequence": "^1.1.0", "style-loader": "^0.12.3", + "url": "^0.10.3", "url-loader": "^0.5.6", - "vinyl-buffer": "^1.0.0", - "vinyl-source-stream": "^1.1.0", - "webpack": "^1.9.10" + "webpack": "^1.9.10", + "webpack-dev-server": "^1.10.1" }, "scripts": { - "lint": "gulp lint", - "start": "gulp", - "test": "karma start test/karma.conf.js --single-run" + "postinstall": "npm run build", + "build": "webpack -p --config webpack.production.config.js", + "start": "node server.js", + "start-production": "NODE_ENV=production node server.js", + "test": "karma start test/karma.conf.js --single-run", + "coveralls": "cat coverage/lcov.info | coveralls", + "lint": "eslint app", + "clean": "rm build/app.js" }, "engines": { "node": ">=0.10.0" diff --git a/client/server.js b/client/server.js new file mode 100644 index 000000000..be2da1a64 --- /dev/null +++ b/client/server.js @@ -0,0 +1,88 @@ +var express = require('express'); +var proxy = require('proxy-middleware'); +var httpProxy = require('express-http-proxy'); +var url = require('url'); + +var app = express(); + + +/************************************************************ + * + * Express routes for: + * - app.js + * - index.html + * + * Proxy requests to: + * - /api -> :4040/api + * + ************************************************************/ + +// Serve application file depending on environment +app.get('/app.js', function(req, res) { + if (process.env.NODE_ENV === 'production') { + res.sendFile(__dirname + '/build/app.js'); + } else { + res.redirect('//localhost:4041/build/app.js'); + } +}); + +// Proxy to backend + +// HACK need express-http-proxy, because proxy-middleware does +// not proxy to /api itself +app.use(httpProxy('localhost:4040', { + filter: function(req) { + return url.parse(req.url).path === '/api'; + }, + forwardPath: function(req) { + return url.parse(req.url).path; + } +})); + +app.use('/api', proxy('http://localhost:4040/api/')); + +// Serve index page + +app.use(express.static('build')); + + +/************************************************************* + * + * Webpack Dev Server + * + * See: http://webpack.github.io/docs/webpack-dev-server.html + * + *************************************************************/ + +if (process.env.NODE_ENV !== 'production') { + var webpack = require('webpack'); + var WebpackDevServer = require('webpack-dev-server'); + var config = require('./webpack.local.config'); + + new WebpackDevServer(webpack(config), { + publicPath: config.output.publicPath, + hot: true, + noInfo: true, + historyApiFallback: true, + stats: { colors: true } + }).listen(4041, 'localhost', function (err, result) { + if (err) { + console.log(err); + } + }); +} + + +/****************** + * + * Express server + * + *****************/ + +var port = process.env.PORT || 4042; +var server = app.listen(port, function () { + var host = server.address().address; + var port = server.address().port; + + console.log('Scope UI listening at http://%s:%s', host, port); +}); diff --git a/client/webpack.config.js b/client/webpack.config.js deleted file mode 100644 index bcca22765..000000000 --- a/client/webpack.config.js +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Webpack config based on https://github.com/kriasoft/react-starter-kit - */ - -'use strict'; - -var autoprefixer = require('autoprefixer-core'); -var _ = require('lodash'); -var webpack = require('webpack'); -var argv = require('minimist')(process.argv.slice(2)); - -var DEBUG = !argv.release; -var STYLE_LOADER = 'style-loader'; -var CSS_LOADER = DEBUG ? 'css-loader' : 'css-loader?minimize'; -var AUTOPREFIXER_LOADER = 'postcss-loader'; - -// -// Common configuration chunk to be used for both -// client-side (app.js) and server-side (server.js) bundles -// ----------------------------------------------------------------------------- - -var config = { - output: { - path: './build/', - publicPath: './', - sourcePrefix: ' ' - }, - - bail: !DEBUG, // fail on first error when building release - cache: DEBUG, - debug: DEBUG, - devtool: DEBUG ? '#inline-source-map' : false, - - stats: { - colors: true, - reasons: DEBUG - }, - - plugins: [ - new webpack.optimize.OccurenceOrderPlugin() - ], - - resolve: { - extensions: ['', '.webpack.js', '.web.js', '.js', '.jsx'] - }, - - module: { - preLoaders: [ - { - test: /\.js$/, - exclude: /node_modules/, - loader: 'eslint-loader' - } - ], - - loaders: [ - { - test: /\.css$/, - loader: STYLE_LOADER + '!' + CSS_LOADER + '!' + AUTOPREFIXER_LOADER - }, - { - test: /\.less$/, - loader: STYLE_LOADER + '!' + CSS_LOADER + '!' + AUTOPREFIXER_LOADER + - '!less-loader' - }, - { - test: /\.gif/, - loader: 'url-loader?limit=10000&mimetype=image/gif' - }, - { - test: /\.jpg/, - loader: 'url-loader?limit=10000&mimetype=image/jpg' - }, - { - test: /\.png/, - loader: 'url-loader?limit=10000&mimetype=image/png' - }, - { - test: /\.svg/, - loader: 'url-loader?limit=10000&mimetype=image/svg+xml' - }, - { - test: /\.jsx?$/, - exclude: /node_modules/, - loader: 'babel-loader' - }, - { - test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, - loader: 'url-loader?limit=10000&minetype=application/font-woff' - }, - { - test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, - loader: 'file-loader' - } - ] - }, - - postcss: [ - autoprefixer({ - browsers: ['last 2 version'] - }) - ] -}; - -// -// Configuration for the client-side bundle (app.js) -// ----------------------------------------------------------------------------- - -var appConfig = _.merge({}, config, { - entry: './app/scripts/main.js', - output: { - filename: 'app.js' - }, - plugins: config.plugins.concat(DEBUG ? [] : [ - new webpack.optimize.DedupePlugin(), - new webpack.optimize.UglifyJsPlugin({compress: {warnings: false}}), - new webpack.optimize.AggressiveMergingPlugin() - ] - ) -}); - -module.exports = [appConfig]; diff --git a/client/webpack.local.config.js b/client/webpack.local.config.js new file mode 100644 index 000000000..7d5af0061 --- /dev/null +++ b/client/webpack.local.config.js @@ -0,0 +1,81 @@ +var webpack = require('webpack'); +var autoprefixer = require('autoprefixer-core'); +var path = require('path'); + +/** + * This is the Webpack configuration file for local development. It contains + * local-specific configuration such as the React Hot Loader, as well as: + * + * - The entry point of the application + * - Where the output file should be + * - Which loaders to use on what files to properly transpile the source + * + * For more information, see: http://webpack.github.io/docs/configuration.html + */ +module.exports = { + + // Efficiently evaluate modules with source maps + devtool: 'eval', + + // Set entry point include necessary files for hot load + entry: [ + 'webpack-dev-server/client?http://localhost:4041', + 'webpack/hot/only-dev-server', + './app/scripts/local' + ], + + // This will not actually create a app.js file in ./build. It is used + // by the dev server for dynamic hot loading. + output: { + path: path.join(__dirname, 'build/'), + filename: 'app.js', + publicPath: 'http://localhost:4041/build/' + }, + + // Necessary plugins for hot load + plugins: [ + new webpack.HotModuleReplacementPlugin(), + new webpack.NoErrorsPlugin() + ], + + // Transform source code using Babel and React Hot Loader + module: { + preLoaders: [ + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'eslint-loader' + } + ], + loaders: [ + { + test: /\.less$/, + loader: 'style-loader!css-loader!postcss-loader!less-loader' + }, + { + test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, + loader: 'url-loader?limit=10000&minetype=application/font-woff' + }, + { + test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, + loader: 'file-loader' + }, + { + test: /\.jsx?$/, + exclude: /node_modules/, + loaders: ['react-hot', 'babel-loader?stage=0'] + } + ] + }, + + postcss: [ + autoprefixer({ + browsers: ['last 2 versions'] + }) + ], + + // Automatically transform files with these extensions + resolve: { + extensions: ['', '.js', '.jsx'] + } +}; diff --git a/client/webpack.production.config.js b/client/webpack.production.config.js new file mode 100644 index 000000000..19f7106a2 --- /dev/null +++ b/client/webpack.production.config.js @@ -0,0 +1,64 @@ +var webpack = require('webpack'); +var autoprefixer = require('autoprefixer-core'); +var path = require('path'); + +/** + * This is the Webpack configuration file for production. + */ +module.exports = { + + // fail on first error when building release + bail: true, + + entry: './app/scripts/main', + + output: { + path: path.join(__dirname, 'build/'), + filename: 'app.js' + }, + + module: { + preLoaders: [ + { + test: /\.js$/, + exclude: /node_modules/, + loader: 'eslint-loader' + } + ], + loaders: [ + { + test: /\.less$/, + loader: 'style-loader!css-loader?minimize!postcss-loader!less-loader' + }, + { + test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, + loader: 'url-loader?limit=10000&minetype=application/font-woff' + }, + { + test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, + loader: 'file-loader' + }, + { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?stage=0' } + ] + }, + + postcss: [ + autoprefixer({ + browsers: ['last 2 versions'] + }) + ], + + eslint: { + failOnError: true + }, + + resolve: { + extensions: ['', '.js', '.jsx'] + }, + + plugins: [new webpack.optimize.UglifyJsPlugin({ + compress: { + warnings: false + } + })] +};