Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Browser support config #3609

Merged
merged 7 commits into from
Mar 27, 2019
Merged

Browser support config #3609

merged 7 commits into from
Mar 27, 2019

Conversation

ranbena
Copy link
Contributor

@ranbena ranbena commented Mar 19, 2019

What type of PR is this?

  • Feature

Fixes #3579

Description

Using browserslist to define which browser versions Redash supports.
List established from minimum "Async function" browser feature support (caniuse).

// package.json
"browserslist": [
  "Edge >= 15",
  "Firefox >= 52",
  "Chrome >= 55",
  "Safari >= 10.1",
  "iOS >= 10.3",
  "Opera >= 42",
  "op_mob >= 46",
  "android >= 67",
  "and_chr >= 71",
  "and_ff >= 64",
  "and_uc >= 11.8",
  "samsung >= 6.2"
]

This list allows us to utilize some powerful tools (all adhering to list automatically):

  • Babel transpiler 🚯

    • js reduced by 2k (comparing app.js on netlify preview)
    • css no change (autoprefix still must use -ms for Edge browser)
    • although babel should drop "async func" and "arrow func" polyfills according to this list - it doesn't. So I excluded these explicitly in .babelrc.
  • Eslint rule - error on unsupported browser feature usage 👮

    • Also available with stylelint but doesn't support less file so whatever man.
  • Outdated browser detection with browserslist-useragent only IE for now🚦

    • redirecting to a dedicated "browser not supported" static page (TBD).

@ghost ghost assigned ranbena Mar 19, 2019
@ghost ghost added the in progress label Mar 19, 2019
@ranbena ranbena requested review from arikfr and kravets-levko March 19, 2019 22:34
import PromiseRejectionError from '@/lib/promise-rejection-error';
import { ErrorHandler } from './error-handler';
import template from './template.html';

if (!matchesUA(navigator.userAgent, { allowHigherVersions: true })) {
// TODO: create "browser outdated" page and redirect to it
console.log('Your browser is outdated', resolveUserAgent(navigator.userAgent));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this the place (and method) to put the redirect?

Copy link
Collaborator

@kravets-levko kravets-levko Mar 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, it's the right place. And probably you don't need a page for redirect: create a component with message or whatever, and conditionally show it instead of <div ng-view>

Copy link
Contributor Author

@ranbena ranbena Mar 20, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But then we're still running potentially unsupported js for that page, which might fail it.
If we early redirect to a static html page, we don't have to worry about it.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you detect UA on client-side - you always have a chance to run unsupported code. If you'll change app-view/template.html to something like this - no change it will render header/footer/page:

<div ng-if="$ctrl.isBrowserSupported">
  <!-- original template here -->
</div>
<div ng-if="!$ctrl.isBrowserSupported">
  Error! Error!!!! Unsupported browser!!!!111
</div>

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's important that app-view component itself shouldn't use any unsupported features, as well as all code it uses via imports.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds easy and simple.
I'll do that and also add a cypress test to make sure it doesn't break.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@kravets-levko does this make sense? (I'd rather it have it's own template)

export default function init(ngModule) {
  ngModule.factory(
    '$exceptionHandler',
    () => function exceptionHandler(exception) {
      handler.process(exception);
    },
  );

  const isBrowserSupported = someCheck(...);
  ngModule.component('appView', {
    template: isBrowserSupported ? template : notSupportedTemplate,
    controller: isBrowserSupported ? AppViewComponent : NotSupportedCtrl,
  });
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ranbena Yes, it's probably even better 👍

@ranbena ranbena mentioned this pull request Mar 20, 2019
1 task
@arikfr
Copy link
Member

arikfr commented Mar 20, 2019 via email

@ranbena
Copy link
Contributor Author

ranbena commented Mar 20, 2019

I think the initial approach of redirect is the correct one.

Best practice would be to determine and redirect in static.py.

@routes.route(org_scoped_rule('/<path:path>'))
@routes.route(org_scoped_rule('/'))
@supported_browser_required  <--
@login_required
def index(**kwargs):
    return render_index()

but that would require re-implementing browserlist-useragent in Python (currently available only in js and ruby).

But going with JS has a clear problem - it's not a standalone file, but a js module.

Options:

  1. Back down and import it into app-view.js.
  2. Implement it in python (and perhaps contribute to the open source project)
  3. Reimplement as standalone js file to be loaded in index.html.

None are perfect, my personal pref is #2 (although not my comfort zone).
Wdyt @arikfr?

@arikfr
Copy link
Member

arikfr commented Mar 20, 2019

Best practice would be to determine and redirect in static.py.

We should avoid depending on our Python server, as ultimately I want to decouple serving the frontend client from the backend server. We already do this decoupling with the preview builds, which are served 100% by Netlify.

So we're left with 1 & 3, and I think option 3 is the most robust option.

@arikfr
Copy link
Member

arikfr commented Mar 20, 2019

Eslint rule - error on unsupported browser feature usage 👮

If we only use browser supported features, what does Babel transpile?

@ranbena
Copy link
Contributor Author

ranbena commented Mar 20, 2019

If we only use browser supported features, what does Babel transpile?

It's a good question and I'd like to know as well. My understanding is that it does not polyfill all features and if a feature is polyfilled (either with dedicated babel plugin / npm package / own util) we need to be explicitly define it to be excluded from the linter.

For instance, if we'd still be targeting IE we'd get a lint error on using Promise but could polyfill it with dedicated package.

@ranbena
Copy link
Contributor Author

ranbena commented Mar 21, 2019

What I want to do

Generate browserslist-useragent.js file that suits old browsers to be loaded in client/app/index.html.

The plan

Define an npm script unsupported:build which transpiles the browserslist-useragent npm package with a dedicated babel config into a single file.

@arikfr

  1. Does this make sense?
  2. Can babel cli transpile a node module with its dependencies? Or can webpack be used to so that?
  3. How do you provide babel with a preset override? (e.g. targets: [ "ie": 8 ])

@arikfr
Copy link
Member

arikfr commented Mar 21, 2019 via email

@ranbena ranbena marked this pull request as ready for review March 21, 2019 08:25
@ranbena
Copy link
Contributor Author

ranbena commented Mar 21, 2019

Tested the redirect method in IE10 and 11 but the rest later this week (with windows machine).

onIE();
}
</script>
<!--[if IE]><script>onIE()</script><![endif]-->
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IE only for now, consider using https://github.com/browserslist/browserslist-useragent in the future.

@ranbena ranbena changed the title Browser support config (wip) Browser support config Mar 21, 2019
@ranbena
Copy link
Contributor Author

ranbena commented Mar 26, 2019

@arikfr made html page static, no template. Lmk if this is what you meant.

@ranbena
Copy link
Contributor Author

ranbena commented Mar 26, 2019

Damnit, another codeclimate eslint plugin problem..
Might have to do with eslint channel compatibility 😒
@arikfr any reason not to switch to CircleCI step instead (assuming it's problem free)?

@ranbena
Copy link
Contributor Author

ranbena commented Mar 26, 2019

Also, @arikfr I put the redirect script in index.html and multi_org.html (dunno what that is).
Should I put it in signed_out.html (a main template) as well?

@ranbena
Copy link
Contributor Author

ranbena commented Mar 26, 2019

@arikfr I don't get the pep8 error here - there are actually 2 lines..

}
},
"//": "browserslist set to 'Async functions' compatibility",
"browserslist": [
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using configuration like we had before (> 0.5%, last 2 versions, Firefox ESR, ie 11, not dead) so we don't have to update this list everytime browser versions update? I mean not necessarily the same one, but along the lines of > 0.5%, last 2 versions etc instead of hardcoded versions.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so we don't have to update this list every time browser versions update

Why would you need to? We should revisit this list when:

  1. There are lower browser versions we would like to support. Won't happen cause we've looked at the browser stats.
  2. As a performance optimization to lower app.js file size. That can be done periodically.

instead of hardcoded version

The advantage of hardcoded versions is that they allow to easily and reliably determine if a user's browser is supported or not. But if we define sth like "last 2 versions" you would have no clear cutoff point (cause under last 2 versions doesn't mean you can't use Redash).

@arikfr arikfr merged commit b5d97e2 into master Mar 27, 2019
@arikfr arikfr deleted the browser branch March 27, 2019 15:47
@arikfr
Copy link
Member

arikfr commented Mar 27, 2019

👍

harveyrendell pushed a commit to pushpay/redash that referenced this pull request Nov 14, 2019
* Browser support config

* Removed some offending code

* Added unsupported html page and redirect for IE

* Typo in regex

* Made html page static

* Added redirect script to multi_org

* Moved static html page to client/app
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Show message when trying to load Redash from an unsupported browser
3 participants