Skip to content

Commit

Permalink
feat: Add browser detection.
Browse files Browse the repository at this point in the history
  • Loading branch information
dotneet committed Apr 11, 2021
1 parent b37912f commit 7565909
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 19 deletions.
43 changes: 36 additions & 7 deletions lib/plugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,26 @@ function isMacOS (a) {
return /Mac OS X/.test(a)
}

// Following regular expressions are copied from bowser(https://github.com/lancedikson/bowser).
// Copyright 2015, Dustin Diaz (the "Original Author")
// https://github.com/lancedikson/bowser/blob/master/LICENSE
const browsers = [
{name: 'Samsung', test: /SamsungBrowser/i },
{name: 'Edge', test: /edg([ea]|ios)/i },
{name: 'Firefox', test: /firefox|iceweasel|fxios/i },
{name: 'Chrome', test: /chrome|crios|crmo/i },
{name: 'Safari', test: /safari|applewebkit/i }
]

function getBrowserName(a) {
for (let b of browsers) {
if (b.test.test(a)) {
return b.name
}
}
return null
}

const DEFAULT_USER_AGENT = '<%= options.defaultUserAgent %>'
const REFRESH_ON_RESIZE = <%= options.refreshOnResize %>

Expand All @@ -43,8 +63,6 @@ function extractDevices (ctx, userAgent = DEFAULT_USER_AGENT) {
let mobileOrTablet = null
let ios = null
let android = null
let windows = false
let macOS = true

if (userAgent === 'Amazon CloudFront') {
if (ctx.req.headers['cloudfront-is-mobile-viewer'] === 'true') {
Expand Down Expand Up @@ -76,10 +94,16 @@ function extractDevices (ctx, userAgent = DEFAULT_USER_AGENT) {
ios = isIos(userAgent)
android = isAndroid(userAgent)
}
windows = isWindows(userAgent)
macOS = isMacOS(userAgent)
const windows = isWindows(userAgent)
const macOS = isMacOS(userAgent)
const browserName = getBrowserName(userAgent)
const isSafari = browserName === 'Safari'
const isFirefox = browserName === 'Firefox'
const isEdge = browserName === 'Edge'
const isChrome = browserName === 'Chrome'
const isSamsung = browserName === 'Samsung'

return { mobile, mobileOrTablet, ios, android, windows, macOS }
return { mobile, mobileOrTablet, ios, android, windows, macOS, isSafari, isFirefox, isEdge, isChrome, isSamsung }
}

export default async function (ctx, inject) {
Expand All @@ -90,7 +114,7 @@ export default async function (ctx, inject) {
} else if (typeof navigator !== 'undefined') {
userAgent = navigator.userAgent
}
const { mobile, mobileOrTablet, ios, android, windows, macOS } = extractDevices(ctx, userAgent)
const { mobile, mobileOrTablet, ios, android, windows, macOS, isSafari, isFirefox, isEdge, isChrome, isSamsung } = extractDevices(ctx, userAgent)
return {
<% if (options.test) { %>
extractDevices,
Expand All @@ -104,7 +128,12 @@ export default async function (ctx, inject) {
isAndroid: android,
isWindows: windows,
isMacOS: macOS,
isDesktopOrTablet: !mobile
isDesktopOrTablet: !mobile,
isSafari,
isFirefox,
isEdge,
isChrome,
isSamsung
}
}
const flags = makeFlags(ctx)
Expand Down
5 changes: 5 additions & 0 deletions lib/types.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ interface Device {
isTablet: boolean
isWindows: boolean
isMacOS: boolean
isSafari: boolean
isFirefox: boolean
isEdge: boolean
isChrome: boolean
isSamsung: boolean
}

declare module '@nuxt/vue-app' {
Expand Down
15 changes: 15 additions & 0 deletions test/fixture/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@
<div v-if="$device.isDesktopOrTablet">
isDesktopOrTablet
</div>
<div v-if="$device.isSafari">
isSafari
</div>
<div v-if="$device.isFirefox">
isFirefox
</div>
<div v-if="$device.isEdge">
isEdge
</div>
<div v-if="$device.isChrome">
isChrome
</div>
<div v-if="$device.isSamsung">
isSamsung
</div>
<pre>{{ JSON.stringify($device, null, 2) }}</pre>
</div>
</template>
27 changes: 15 additions & 12 deletions test/module.test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
const { setup, loadConfig, url } = require('@nuxtjs/module-test-utils')

const defaultOsSettings = { android: null, ios: null, macOS: true, windows: false }
const defaultOsSettings = { android: null, ios: null, macOS: false, windows: false }
const defaultBrowserFlags = { isChrome: false, isEdge: false, isFirefox: false, isSafari: false, isSamsung: false }
const createBrowserFlags = (override) => {
return { ...defaultBrowserFlags, ...override }
}

describe('Device module', () => {
let nuxt
Expand Down Expand Up @@ -38,31 +42,31 @@ describe('Device module', () => {
it('Samsung Galaxy S9', () => {
const userAgent = 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G960F Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36'

expect(extractDevices(ctx, userAgent)).toEqual({ mobile: true, mobileOrTablet: true, android: true, ios: false, macOS: false, windows: false })
expect(extractDevices(ctx, userAgent)).toEqual({ mobile: true, mobileOrTablet: true, android: true, ios: false, macOS: false, windows: false, ...createBrowserFlags({ isChrome: true }) })
})

it('Apple iPhone X', () => {
const userAgent = 'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1'

expect(extractDevices(ctx, userAgent)).toEqual({ mobile: true, mobileOrTablet: true, android: false, ios: true, macOS: true, windows: false })
expect(extractDevices(ctx, userAgent)).toEqual({ mobile: true, mobileOrTablet: true, android: false, ios: true, macOS: true, windows: false, ...createBrowserFlags({ isSafari: true }) })
})

it('Samsung Galaxy Tab S3', () => {
const userAgent = 'Mozilla/5.0 (Linux; Android 7.0; SM-T827R4 Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.116 Safari/537.36'

expect(extractDevices(ctx, userAgent)).toEqual({ mobile: false, mobileOrTablet: true, android: true, ios: false, macOS: false, windows: false })
expect(extractDevices(ctx, userAgent)).toEqual({ mobile: false, mobileOrTablet: true, android: true, ios: false, macOS: false, windows: false, ...createBrowserFlags({ isChrome: true }) })
})

it('Windows 10-based PC using Edge browser', () => {
const userAgent = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246'

expect(extractDevices(ctx, userAgent)).toEqual({ mobile: false, mobileOrTablet: false, android: false, ios: false, macOS: false, windows: true })
expect(extractDevices(ctx, userAgent)).toEqual({ mobile: false, mobileOrTablet: false, android: false, ios: false, macOS: false, windows: true, ...createBrowserFlags({ isEdge: true }) })
})

it('Mac OS X-based computer using a Safari browser', () => {
const userAgent = 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/601.3.9 (KHTML, like Gecko) Version/9.0.2 Safari/601.3.9'

expect(extractDevices(ctx, userAgent)).toEqual({ mobile: false, mobileOrTablet: false, android: false, ios: false, macOS: true, windows: false })
expect(extractDevices(ctx, userAgent)).toEqual({ mobile: false, mobileOrTablet: false, android: false, ios: false, macOS: true, windows: false, ...createBrowserFlags({ isSafari: true }) })
})
})

Expand All @@ -71,25 +75,24 @@ describe('Device module', () => {
const userAgent =
'Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15A372 Instagram';

expect(extractDevices(ctx, userAgent)).toEqual({ mobile: true, mobileOrTablet: true, android: false, ios: true, macOS: true, windows: false })
expect(extractDevices(ctx, userAgent)).toEqual({ mobile: true, mobileOrTablet: true, android: false, ios: true, macOS: true, windows: false, ...createBrowserFlags( { isSafari: true })})
})
it('Facebook', () => {
const userAgent =
"Mozilla/5.0 ((iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit (KHTML, like Gecko) Mobile [FBAN/FBForIPhone;FBAV/4.1;FBBV/4100.0;FBDV/iPhone3,1;FBMD/iPhone;FBSN/iPhone OS;FBSV/5.1.1;FBSS/2; tablet;FBLC/en_US]";

expect(extractDevices(ctx, userAgent)).toEqual({ mobile: true, mobileOrTablet: true, android: false, ios: true, macOS: true, windows: false })
expect(extractDevices(ctx, userAgent)).toEqual({ mobile: true, mobileOrTablet: true, android: false, ios: true, macOS: true, windows: false, ...createBrowserFlags({ isSafari: true })})
})
})

it('detects cloudflare headers', () => {
headers['cf-device-type'] = 'mobile'

expect(extractDevices(ctx)).toEqual({ mobile: true, mobileOrTablet: true, ...defaultOsSettings })
expect(extractDevices(ctx, '')).toEqual({ mobile: true, mobileOrTablet: true, ...defaultOsSettings, ...defaultBrowserFlags })

headers['cf-device-type'] = 'tablet'
expect(extractDevices(ctx)).toEqual({ mobile: false, mobileOrTablet: true, ...defaultOsSettings })
expect(extractDevices(ctx, '')).toEqual({ mobile: false, mobileOrTablet: true, ...defaultOsSettings, ...defaultBrowserFlags })

headers['cf-device-type'] = 'desktop'
expect(extractDevices(ctx)).toEqual({ mobile: false, mobileOrTablet: false, ...defaultOsSettings })
expect(extractDevices(ctx, '')).toEqual({ mobile: false, mobileOrTablet: false, ...defaultOsSettings, ...defaultBrowserFlags })
})
})

0 comments on commit 7565909

Please sign in to comment.