diff --git a/.dockerignore b/.dockerignore index 8eaa766..3f2b265 100644 --- a/.dockerignore +++ b/.dockerignore @@ -6,7 +6,7 @@ tmp/ node_modules/ ################################## -# +# # rest is COPIED from .gitignore # ################################## @@ -62,4 +62,4 @@ package-lock.json /public/sitemap.xml.gz # Development Docker storage location -_docker-storage/ \ No newline at end of file +# _docker-storage/ \ No newline at end of file diff --git a/Procfile.local_prod b/Procfile.local_prod new file mode 100644 index 0000000..d6ee069 --- /dev/null +++ b/Procfile.local_prod @@ -0,0 +1,2 @@ +web: bundle exec rails server -p 3000 +worker: bundle exec rake jobs:work \ No newline at end of file diff --git a/_Dockerfile b/_Dockerfile new file mode 100644 index 0000000..01b2c2b --- /dev/null +++ b/_Dockerfile @@ -0,0 +1,49 @@ +FROM alpine:latest + +LABEL Alec Pervushin + +ENV RUBY_INSTALL_VERSION "0.7.0" +ENV RUBY_INSTALL_URL "https://github.com/postmodern/ruby-install/archive/v${RUBY_INSTALL_VERSION}.tar.gz" +ENV CHRUBY_VERSION '0.3.9' +ENV CHRUBY_URL "https://github.com/postmodern/chruby/archive/v${CHRUBY_VERSION}.tar.gz" + +RUN apk update && \ + apk upgrade && \ + apk add --no-cache gnupg curl bash procps musl zlib openssl \ + patch make gcc g++ gnupg musl-dev linux-headers zlib-dev openssl-dev \ + postgresql-dev tzdata ruby readline-dev git nodejs yarn + +SHELL ["/bin/bash", "-lc"] + +WORKDIR /tmp + +RUN curl -L -o ruby-install.tar.gz ${RUBY_INSTALL_URL} && \ + tar -xzvf ruby-install.tar.gz && \ + cd ruby-install-${RUBY_INSTALL_VERSION}/ && make install + +ADD _docker-storage/current.tgz* /opt/ + +COPY _docker-storage/install-railsexpress* /tmp/ +COPY .ruby-version* /root/ +COPY Gemfile* /tmp/ + +RUN echo 'export RUBY_VERSION=$([ -z "$RUBY_VERSION" ] && cat ~/.ruby-version || "$RUBY_VERSION")' >> /etc/profile + +ENV THREAD_PATCH "https://bugs.ruby-lang.org/attachments/download/7081/0001-thread_pthread.c-make-get_main_stack-portable-on-lin.patch" + +RUN ./install-railsexpress railsexpress $RUBY_VERSION \ + -p ${THREAD_PATCH} --jobs=2 --cleanup --no-reinstall + +RUN curl -L -o chruby.tar.gz ${CHRUBY_URL} && \ + tar -xzvf chruby.tar.gz && \ + cd chruby-${CHRUBY_VERSION}/ && make install && \ + echo "source /usr/local/share/chruby/chruby.sh" >> /etc/profile && \ + echo 'chruby $RUBY_VERSION' >> /etc/profile + +RUN gem install bundler rb-readline && bundle check || \ + bundle install && gem install foreman + +RUN apk del gnupg musl-dev linux-headers ruby && \ + rm -rf /tmp/* /var/cache/apk/* + +COPY _docker-entrypoint.sh* / \ No newline at end of file diff --git a/_docker-compose.yml b/_docker-compose.yml new file mode 100644 index 0000000..279f72f --- /dev/null +++ b/_docker-compose.yml @@ -0,0 +1,145 @@ +version: "3.7" + +services: + rails: + build: + context: . + dockerfile: _Dockerfile + stdin_open: true + tty: true + working_dir: /usr/src/app + networks: + courses-network: + aliases: + - rails + ports: + - 127.0.1.1:3000:3000 + volumes: + - .:/usr/src/app + - rubies:/opt/rubies + depends_on: + - db + - cache + - arc + environment: + RAILS_ENV: "local_production" + RACK_ENV: "local_production" + DATABASE_URL: "postgres://postgres:password@db/" + MEMCACHIER_SERVERS: "cache" + # ENABLE_HTTPS: "true" + RAILS_SERVE_STATIC_FILES: "true" + RAILS_LOG_TO_STDOUT: "true" + YARN_INTEGRITY_ENABLED: "false" + entrypoint: /_docker-entrypoint.sh + command: "bin/startup" + + app: + image: nginx:1.15.12-alpine + depends_on: + - rails + networks: + courses-network: + aliases: + - app + volumes: + - ./_docker-storage/certs:/etc/nginx/certs + - ./_docker-storage/ssl.conf:/etc/nginx/conf.d/ssl.conf + ports: + - 127.0.1.1:3443:443 + + db: + image: postgres:10-alpine + networks: + courses-network: + aliases: + - db + + cache: + image: memcached:1.5.12-alpine + networks: + courses-network: + aliases: + - cache + + arc: + image: alpine:latest + volumes: + - rubies:/cont/rubies + - ./_docker-storage:/host/docker + networks: + - courses-network + working_dir: /cont + entrypoint: tar -czf /host/docker/current.tgz rubies/ + + pghero: + image: ankane/pghero + depends_on: + - db + ports: + - 127.0.1.1:8080:8080 + environment: + DATABASE_URL: "postgres://postgres:password@db/PracticalDeveloper_development" + networks: + - courses-network + + sitespeed.io: + image: sitespeedio/sitespeed.io + networks: + - courses-network + command: -V + shm_size: 1g + volumes: + - ./sitespeed-result/:/sitespeed.io/sitespeed-result + + grafana: + image: grafana/grafana:6.1.6 + depends_on: + - graphite + networks: + - courses-network + ports: + - "127.0.1.1:3000:3000" + environment: + - GF_SECURITY_ADMIN_PASSWORD=hdeAga76VG6ga7plZ1 + - GF_SECURITY_ADMIN_USER=sitespeedio + - GF_AUTH_ANONYMOUS_ENABLED=true + - GF_USERS_ALLOW_SIGN_UP=false + - GF_USERS_ALLOW_ORG_CREATE=false + volumes: + - grafana:/var/lib/grafana + + graphite: + image: sitespeedio/graphite:1.1.5-3 + networks: + - courses-network + ports: + - "127.0.1.1:2003:2003" + - "127.0.1.1:8080:80" + volumes: + # In production you should configure/map these to your container + # Make sure whisper and graphite.db/grafana.db lives outside your containerr + # https://www.sitespeed.io/documentation/sitespeed.io/graphite/#graphite-for-production-important + - whisper:/opt/graphite/storage/whisper + # Download an empty graphite.db from https://github.com/sitespeedio/sitespeed.io/tree/master/docker/graphite + #- ./graphite/graphite.db:/opt/graphite/storage/graphite.db + #- ./graphite/conf/storage-schemas.conf:/opt/graphite/conf/storage-schemas.conf + #- ./graphite/conf/storage-aggregation.conf:/opt/graphite/conf/storage-aggregation.conf + #- ./graphite/conf/carbon.conf:/opt/graphite/conf/carbon.conf + grafana-setup: + image: sitespeedio/grafana-bootstrap:8.14.0 + networks: + - courses-network + depends_on: + - grafana + environment: + - GF_PASSWORD=hdeAga76VG6ga7plZ1 + - GF_USER=sitespeedio + +networks: + courses-network: + name: courses-network + +volumes: + rubies: + grafana: + whisper: diff --git a/_docker-entrypoint.sh b/_docker-entrypoint.sh new file mode 100755 index 0000000..28a3d0c --- /dev/null +++ b/_docker-entrypoint.sh @@ -0,0 +1,6 @@ +#! /bin/bash -l + +chruby + +# Execute the given or default command: +exec "$@" \ No newline at end of file diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index fdad052..915af05 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -83,7 +83,7 @@ def icon_url(name) end def cloudinary(url, width = nil, _quality = 80, _format = "jpg") - return url if Rails.env.development? && (url.blank? || url.exclude?("http")) + return url if (Rails.env.development? || Rails.env.local_production?) && (url.blank? || url.exclude?("http")) service_path = "https://res.cloudinary.com/practicaldev/image/fetch" @@ -101,7 +101,7 @@ def cloudinary(url, width = nil, _quality = 80, _format = "jpg") def cloud_cover_url(url) return if url.blank? return asset_path("triple-unicorn") if Rails.env.test? - return url if Rails.env.development? + return url if Rails.env.development? || Rails.env.local_production? width = 1000 height = 420 diff --git a/app/javascript/packs/proCharts.js b/app/javascript/packs/proCharts.js index 154ef68..9081feb 100644 --- a/app/javascript/packs/proCharts.js +++ b/app/javascript/packs/proCharts.js @@ -1,93 +1,102 @@ -import Chart from 'chart.js'; +const [ + reactionsChart, + commentsChart, +] = import(/* webpackChunkName: 'moment' */ 'chart.js').then( + ({ default: Chart }) => { + const reactionsCanvas = document.getElementById('reactionsChart'); + const commentsCanvas = document.getElementById('commentsChart'); -const reactionsCanvas = document.getElementById('reactionsChart'); -const commentsCanvas = document.getElementById('commentsChart'); - -export const reactionsChart = new Chart(reactionsCanvas, { - type: 'line', - data: { - labels: JSON.parse(reactionsCanvas.dataset.labels), - datasets: [ - { - label: 'Reaction Total', - data: JSON.parse(reactionsCanvas.dataset.totalCount), - // data: [5, 10, 15, 17, 25, 23], - fill: false, - borderColor: 'rgb(75, 192, 192)', - lineTension: 0.1, - }, - { - label: 'Total Likes', - data: JSON.parse(reactionsCanvas.dataset.totalLikes), - // data: [2, 5, 10, 10, 15, 13], - fill: false, - borderColor: 'rgb(229, 100, 100)', - lineTension: 0.1, - }, - { - label: 'Total Unicorns', - data: JSON.parse(reactionsCanvas.dataset.totalUnicorns), - // data: [1, 2, 2, 4, 5, 3], - fill: false, - borderColor: 'rgb(157, 57, 233)', - lineTension: 0.1, - }, - { - label: 'Total Bookmarks', - data: JSON.parse(reactionsCanvas.dataset.totalReadinglist), - // data: [2, 3, 3, 3, 5, 7], - fill: false, - borderColor: 'rgb(10, 133, 255)', - lineTension: 0.1, - }, - ], - }, - options: { - title: { - display: true, - text: 'Reactions over the Last Week', - }, - scales: { - yAxes: [ - { - ticks: { - suggestedMin: 0, - precision: 0, + const entityReactionsChart = new Chart(reactionsCanvas, { + type: 'line', + data: { + labels: JSON.parse(reactionsCanvas.dataset.labels), + datasets: [ + { + label: 'Reaction Total', + data: JSON.parse(reactionsCanvas.dataset.totalCount), + // data: [5, 10, 15, 17, 25, 23], + fill: false, + borderColor: 'rgb(75, 192, 192)', + lineTension: 0.1, + }, + { + label: 'Total Likes', + data: JSON.parse(reactionsCanvas.dataset.totalLikes), + // data: [2, 5, 10, 10, 15, 13], + fill: false, + borderColor: 'rgb(229, 100, 100)', + lineTension: 0.1, + }, + { + label: 'Total Unicorns', + data: JSON.parse(reactionsCanvas.dataset.totalUnicorns), + // data: [1, 2, 2, 4, 5, 3], + fill: false, + borderColor: 'rgb(157, 57, 233)', + lineTension: 0.1, }, + { + label: 'Total Bookmarks', + data: JSON.parse(reactionsCanvas.dataset.totalReadinglist), + // data: [2, 3, 3, 3, 5, 7], + fill: false, + borderColor: 'rgb(10, 133, 255)', + lineTension: 0.1, + }, + ], + }, + options: { + title: { + display: true, + text: 'Reactions over the Last Week', + }, + scales: { + yAxes: [ + { + ticks: { + suggestedMin: 0, + precision: 0, + }, + }, + ], }, - ], - }, - }, -}); - -export const commentsChart = new Chart(commentsCanvas, { - type: 'line', - data: { - labels: JSON.parse(commentsCanvas.dataset.labels), - datasets: [ - { - label: 'Total Comments', - data: JSON.parse(commentsCanvas.dataset.totalCount), - fill: false, - borderColor: 'rgb(75, 192, 192)', - lineTension: 0.1, }, - ], - }, - options: { - title: { - display: true, - text: 'Comments over the Last Week', - }, - scales: { - yAxes: [ - { - ticks: { - suggestedMin: 0, - precision: 0, + }); + + const entityCommentsChart = new Chart(commentsCanvas, { + type: 'line', + data: { + labels: JSON.parse(commentsCanvas.dataset.labels), + datasets: [ + { + label: 'Total Comments', + data: JSON.parse(commentsCanvas.dataset.totalCount), + fill: false, + borderColor: 'rgb(75, 192, 192)', + lineTension: 0.1, }, + ], + }, + options: { + title: { + display: true, + text: 'Comments over the Last Week', + }, + scales: { + yAxes: [ + { + ticks: { + suggestedMin: 0, + precision: 0, + }, + }, + ], }, - ], - }, + }, + }); + + return [entityReactionsChart, entityCommentsChart]; }, -}); +); + +export { reactionsChart, commentsChart }; diff --git a/bin/startup b/bin/startup index c7e84ef..30acac0 100755 --- a/bin/startup +++ b/bin/startup @@ -10,7 +10,11 @@ def system!(*args) system(*args) || abort("\n== Command #{args} failed ==") end +procfile = 'Procfile.falcon' if ENV['RACK_HANDLER'] +procfile ||= + ENV['RAILS_ENV'] == 'local_production' ? 'Procfile.local_prod' : 'Procfile.dev' + chdir APP_ROOT do puts "== STARTING UP ==" - system! "foreman start -f Procfile.dev" -end + system! "foreman start -f #{procfile}" +end \ No newline at end of file diff --git a/config/environments/local_production.rb b/config/environments/local_production.rb new file mode 100644 index 0000000..5e53349 --- /dev/null +++ b/config/environments/local_production.rb @@ -0,0 +1,119 @@ +Rails.application.configure do + # Verifies that versions and hashed value of the package contents in the project's package.json + config.webpacker.check_yarn_integrity = false + + # Settings specified here will take precedence over those in config/application.rb. + + # Code is not reloaded between requests. + config.cache_classes = true + + # Eager load code on boot. This eager loads most of Rails and + # your application in memory, allowing both threaded web servers + # and those relying on copy on write to perform better. + # Rake tasks automatically ignore this option for performance. + config.eager_load = true + + # Full error reports are disabled and caching is turned on. + config.consider_all_requests_local = false + config.action_controller.perform_caching = true + + # Enable Rack::Cache to put a simple HTTP cache in front of your application + # Add `rack-cache` to your Gemfile before enabling this. + # For large-scale production use, consider using a caching reverse proxy like + # NGINX, varnish or squid. + # config.action_dispatch.rack_cache = true + config.read_encrypted_secrets = true + + # Disable serving static files from the `/public` folder by default since + # Apache or NGINX already handles this. + config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present? + config.public_file_server.headers = { + "Cache-Control" => "public, s-maxage=2592000, max-age=86400" + } + + # Compress JavaScripts and CSS. + config.assets.js_compressor = Uglifier.new(harmony: true) + # config.assets.css_compressor = :sass + + # Do not fallback to assets pipeline if a precompiled asset is missed. + config.assets.compile = true + + # Asset digests allow you to set far-future HTTP expiration dates on all assets, + # yet still be able to expire them through the digest params. + config.assets.digest = true + + # `config.assets.precompile` and `config.assets.version` + # have moved to config/initializers/assets.rb + + # Specifies the header that your server uses for sending files. + # config.action_dispatch.x_sendfile_header = 'X-Sendfile' # for Apache + # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX + + # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies. + if ENV['ENABLE_HTTPS'].present? + config.force_ssl = true + config.ssl_options = { hsts: { expires: 3600 } } + end + + # Use the lowest log level to ensure availability of diagnostic information + # when problems arise. + config.log_level = :debug + + # Prepend all log lines with the following tags. + config.log_tags = [:request_id] + + # Use a different logger for distributed setups. + # config.logger = ActiveSupport::TaggedLogging.new(SyslogLogger.new) + + # Use a different cache store in production. + # config.cache_store = :mem_cache_store + + # Enable serving of images, stylesheets, and JavaScripts from an asset server. + config.action_mailer.perform_caching = false + + # Ignore bad email addresses and do not raise email delivery errors. + # Set this to true and configure the email server for immediate delivery to raise delivery errors. + # config.action_mailer.raise_delivery_errors = false + + # Enable locale fallbacks for I18n (makes lookups for any locale fall back to + # the I18n.default_locale when a translation cannot be found). + config.i18n.fallbacks = [I18n.default_locale] + + # Send deprecation notices to registered listeners. + config.active_support.deprecation = :notify + + # Use default logging formatter so that PID and timestamp are not suppressed. + # config.log_formatter = ::Logger::Formatter.new + config.log_formatter = ::Logger::Formatter.new + if ENV["RAILS_LOG_TO_STDOUT"].present? + logger = ActiveSupport::Logger.new(STDOUT) + logger.formatter = config.log_formatter + config.logger = ActiveSupport::TaggedLogging.new(logger) + end + + # Do not dump schema after migrations. + config.active_record.dump_schema_after_migration = false + + config.cache_store = :dalli_store, + (ENV["MEMCACHIER_SERVERS"] || "").split(","), + { username: ENV["MEMCACHIER_USERNAME"], + password: ENV["MEMCACHIER_PASSWORD"], + failover: true, + socket_timeout: 1.5, + socket_failure_delay: 0.2 } + + config.app_domain = ENV["APP_DOMAIN"] + + config.action_mailer.delivery_method = :smtp + config.action_mailer.perform_deliveries = true + config.action_mailer.default_url_options = { host: ENV["APP_PROTOCOL"] + ENV["APP_DOMAIN"] } + ActionMailer::Base.smtp_settings = { + address: "smtp.sendgrid.net", + port: "587", + authentication: :plain, + user_name: ENV["SENDGRID_USERNAME_ACCEL"], + password: ENV["SENDGRID_PASSWORD_ACCEL"], + domain: "dev.to", + enable_starttls_auto: true + } +end diff --git a/config/initializers/airbrake.rb b/config/initializers/airbrake.rb index 0a3fffc..ad5d88e 100644 --- a/config/initializers/airbrake.rb +++ b/config/initializers/airbrake.rb @@ -1,3 +1,5 @@ +return if Rails.env.local_production? + # Airbrake is an online tool that provides robust exception tracking in your Rails # applications. In doing so, it allows you to easily review errors, tie an error # to an individual piece of code, and trace the cause back to recent diff --git a/config/initializers/carrierwave.rb b/config/initializers/carrierwave.rb index 9e191ac..31983c6 100644 --- a/config/initializers/carrierwave.rb +++ b/config/initializers/carrierwave.rb @@ -3,7 +3,7 @@ require "carrierwave/storage/fog" CarrierWave.configure do |config| - if Rails.env.development? || Rails.env.test? + if Rails.env.development? || Rails.env.test? || Rails.env.local_production? config.storage = :file else # config.fog_provider = 'fog-aws' diff --git a/config/secrets.yml b/config/secrets.yml index 73f5e05..4e921d6 100644 --- a/config/secrets.yml +++ b/config/secrets.yml @@ -16,6 +16,8 @@ development: test: secret_key_base: 42dd7834039ebbea271af22635a6782ee15e519b14629c5276bfcdd4cff841e9926994784bb43a335a8f8c9739bb254ea3afe831839d4dc65654ec7516ec25f0 +local_production: + secret_key_base: a60edc976c913b19fd9fc8118936fbe1df2b07f4eecc5ad32f975e33cd4ea36b150c1ce933b681b90874a46568041629003dcbfc07238f7dca91741bcd1ec870 # Do not keep production secrets in the repository, # instead read values from the environment. diff --git a/package.json b/package.json index d759e54..0f4ebe9 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ "test": "jest app/javascript/ --coverage", "test:watch": "jest app/javascript/ --watch", "storybook": "start-storybook -p 6006 -c app/javascript/.storybook -s app/javascript/.storybook/assets", - "build-storybook": "build-storybook -c app/javascript/.storybook -s app/javascript/.storybook/assets" + "build-storybook": "build-storybook -c app/javascript/.storybook -s app/javascript/.storybook/assets", + "analyze": "bin/webpack --config config/webpack/production.js --profile --json > tmp/stats.json && webpack-bundle-analyzer tmp/stats.json public/packs -m static -r tmp/report-webpack.html -O" }, "husky": { "hooks": { @@ -82,7 +83,8 @@ "preact-render-spy": "^1.3.0", "preact-render-to-json": "^3.6.6", "prettier": "^1.16.4", - "webpack-dev-server": "^2.11.3" + "webpack-dev-server": "^2.11.3", + "webpack-bundle-analyzer": "^3.3.2" }, "dependencies": { "@rails/webpacker": "^3.5.5", diff --git a/sitespeed-result/homeBudget.json b/sitespeed-result/homeBudget.json new file mode 100644 index 0000000..b9cd551 --- /dev/null +++ b/sitespeed-result/homeBudget.json @@ -0,0 +1,7 @@ +{ + "budget": { + "transferSize": { + "javascript": 460000 + } + } +} diff --git a/yarn.lock b/yarn.lock index fd028ff..faf743a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -692,7 +692,7 @@ acorn-jsx@^5.0.0: resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e" integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg== -acorn-walk@^6.0.1: +acorn-walk@^6.0.1, acorn-walk@^6.1.1: version "6.1.1" resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-6.1.1.tgz#d363b66f5fac5f018ff9c3a1e7b6f8e310cc3913" integrity sha512-OtUw6JUTgxA2QoqqmrmQ7F2NYqiBPi/L2jqHyFtllhOUvXYQXf0Z1CYUinIfyT4bTCGmrA7gX9FvHA81uzCoVw== @@ -2247,6 +2247,16 @@ bcrypt-pbkdf@^1.0.0: dependencies: tweetnacl "^0.14.3" +bfj@^6.1.1: + version "6.1.1" + resolved "https://registry.yarnpkg.com/bfj/-/bfj-6.1.1.tgz#05a3b7784fbd72cfa3c22e56002ef99336516c48" + integrity sha512-+GUNvzHR4nRyGybQc2WpNJL4MJazMuvf92ueIyA0bIkPRwhhQu3IfZQ2PSoVPpCBJfmoSdOxu5rnotfFLlvYRQ== + dependencies: + bluebird "^3.5.1" + check-types "^7.3.0" + hoopy "^0.1.2" + tryer "^1.0.0" + big.js@^3.1.3: version "3.2.0" resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e" @@ -2723,6 +2733,11 @@ chartjs-color@^2.1.0: chartjs-color-string "^0.5.0" color-convert "^0.5.3" +check-types@^7.3.0: + version "7.4.0" + resolved "https://registry.yarnpkg.com/check-types/-/check-types-7.4.0.tgz#0378ec1b9616ec71f774931a3c6516fad8c152f4" + integrity sha512-YbulWHdfP99UfZ73NcUDlNJhEIDgm9Doq9GhpyXbF+7Aegi3CVV7qqMCKTTqJxlvEvnQBp9IA+dxsGN6xK/nSg== + chokidar@^2.0.0, chokidar@^2.0.2: version "2.0.4" resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.0.4.tgz#356ff4e2b0e8e43e322d18a372460bbcf3accd26" @@ -2996,6 +3011,11 @@ commander@^2.11.0, commander@^2.14.1, commander@^2.15.0, commander@^2.19.0, comm resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a" integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg== +commander@^2.18.0: + version "2.20.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== + commander@~2.13.0: version "2.13.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.13.0.tgz#6964bca67685df7c1f1430c584f07d7597885b9c" @@ -3842,6 +3862,11 @@ ee-first@1.1.1: resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= +ejs@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.6.1.tgz#498ec0d495655abc6f23cd61868d926464071aa0" + integrity sha512-0xy4A/twfrRCnkhfk8ErDi5DqdAsAqeGxht4xkCUrsvhhbQNs7E+4jV0CN7+NKIY0aHE72+XvqtBIXzD31ZbXQ== + electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.30, electron-to-chromium@^1.3.47: version "1.3.96" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.96.tgz#25770ec99b8b07706dedf3a5f43fa50cb54c4f9a" @@ -4664,6 +4689,11 @@ filesize@3.5.11: resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.11.tgz#1919326749433bb3cf77368bd158caabcc19e9ee" integrity sha512-ZH7loueKBoDb7yG9esn1U+fgq7BzlzW6NRi5/rMdxIZ05dj7GFD/Xc5rq2CDt5Yq86CyfSYVyx4242QQNZbx1g== +filesize@^3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.6.1.tgz#090bb3ee01b6f801a8a8be99d31710b3422bb317" + integrity sha512-7KjR1vv6qnicaPMi1iiTcI85CyYwRO/PSFCu6SvqL8jN2Wjt/NIYQTFtFs7fSDCYOstUkEWIQGFUg5YZQfjlcg== + fill-range@^2.1.0: version "2.2.4" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.4.tgz#eb1e773abb056dcd8df2bfdf6af59b8b3a936565" @@ -5147,6 +5177,14 @@ gzip-size@3.0.0: dependencies: duplexer "^0.1.1" +gzip-size@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-5.1.0.tgz#2db0396c71f5c902d5cf6b52add5030b93c99bd2" + integrity sha512-wfSnvypBDRW94v5W3ckvvz/zFUNdJ81VgOP6tE4bPpRUcc0wGqU+y0eZjJEvKxwubJFix6P84sE8M51YWLT7rQ== + dependencies: + duplexer "^0.1.1" + pify "^4.0.1" + handle-thing@^1.2.5: version "1.2.5" resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-1.2.5.tgz#fd7aad726bf1a5fd16dfc29b2f7a6601d27139c4" @@ -5328,6 +5366,11 @@ homedir-polyfill@^1.0.1: dependencies: parse-passwd "^1.0.0" +hoopy@^0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/hoopy/-/hoopy-0.1.4.tgz#609207d661100033a9a9402ad3dea677381c1b1d" + integrity sha512-HRcs+2mr52W0K+x8RzcLzuPPmVIKMSv97RGHy0Ea9y/mpcaK+xTrjICA04KAHi4GRzxliNqNJEFYWHghy3rSfQ== + hosted-git-info@^2.1.4: version "2.7.1" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047" @@ -7980,6 +8023,11 @@ onetime@^2.0.0: dependencies: mimic-fn "^1.0.0" +opener@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.1.tgz#6d2f0e77f1a0af0032aca716c2c1fbb8e7e8abed" + integrity sha512-goYSy5c2UXE4Ra1xixabeVh1guIX/ZV/YokJksb6q2lubWu6UbvPQ20p542/sFIll1nl8JnCyK9oBaOcCWXwvA== + opn@5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/opn/-/opn-5.2.0.tgz#71fdf934d6827d676cecbea1531f95d354641225" @@ -8316,6 +8364,11 @@ pify@^3.0.0: resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= +pify@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== + pinkie-promise@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" @@ -11174,6 +11227,11 @@ trim@0.0.1: dependencies: glob "^7.1.2" +tryer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tryer/-/tryer-1.0.1.tgz#f2c85406800b9b0f74c9f7465b81eaad241252f8" + integrity sha512-c3zayb8/kWWpycWYg87P71E1S1ZL6b6IJxfb5fvsUgsf0S2MVGaDhDXXjDMpdCpfWXqptc+4mXwmiy1ypXqRAA== + tslib@^1.9.0: version "1.9.3" resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.9.3.tgz#d7e4dd79245d85428c4d7e4822a79917954ca286" @@ -11579,6 +11637,25 @@ webidl-conversions@^4.0.2: resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== +webpack-bundle-analyzer@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-3.3.2.tgz#3da733a900f515914e729fcebcd4c40dde71fc6f" + integrity sha512-7qvJLPKB4rRWZGjVp5U1KEjwutbDHSKboAl0IfafnrdXMrgC0tOtZbQD6Rw0u4cmpgRN4O02Fc0t8eAT+FgGzA== + dependencies: + acorn "^6.0.7" + acorn-walk "^6.1.1" + bfj "^6.1.1" + chalk "^2.4.1" + commander "^2.18.0" + ejs "^2.6.1" + express "^4.16.3" + filesize "^3.6.1" + gzip-size "^5.0.0" + lodash "^4.17.10" + mkdirp "^0.5.1" + opener "^1.5.1" + ws "^6.0.0" + webpack-dev-middleware@1.12.2, webpack-dev-middleware@^1.12.2: version "1.12.2" resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz#f8fc1120ce3b4fc5680ceecb43d777966b21105e" @@ -11839,6 +11916,13 @@ ws@^5.2.0: dependencies: async-limiter "~1.0.0" +ws@^6.0.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-6.2.1.tgz#442fdf0a47ed64f59b6a5d8ff130f4748ed524fb" + integrity sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA== + dependencies: + async-limiter "~1.0.0" + ws@^6.1.2: version "6.1.2" resolved "https://registry.yarnpkg.com/ws/-/ws-6.1.2.tgz#3cc7462e98792f0ac679424148903ded3b9c3ad8"