@clappr/hlsjs-playback 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clappr/hlsjs-playback",
3
- "version": "2.0.0",
3
+ "version": "3.0.0",
4
4
  "description": "HLS Playback based on hls.js",
5
5
  "main": "./dist/hlsjs-playback.js",
6
6
  "module": "./dist/hlsjs-playback.esm.js",
@@ -10,8 +10,9 @@
10
10
  "build": "rollup --config --bundleConfigAsCjs",
11
11
  "watch": "rollup --config --bundleConfigAsCjs --watch",
12
12
  "bundle-check": "ANALYZE_BUNDLE=true rollup --config --bundleConfigAsCjs",
13
- "release": "MINIMIZE=true rollup --config --bundleConfigAsCjs",
14
- "test": "jest ./src --testPathIgnorePatterns=dist.smoke --coverage --silent && yarn release && jest ./src/dist.smoke.test.js --silent",
13
+ "release": "rm -rf dist && MINIMIZE=true rollup --config --bundleConfigAsCjs",
14
+ "test": "jest ./src --coverage --silent",
15
+ "test:smoke": "jest ./src/dist.smoke.test.js --testPathIgnorePatterns=/node_modules/ --silent",
15
16
  "test:watch": "jest ./src --watch",
16
17
  "lint": "eslint *.js ./src",
17
18
  "lint:fix": "yarn lint -- --fix",
@@ -37,12 +38,12 @@
37
38
  "homepage": "https://github.com/clappr/hlsjs-playback",
38
39
  "peerDependencies": {
39
40
  "@clappr/core": "*",
40
- "hls.js": "1.6.16"
41
+ "hls.js": "^1"
41
42
  },
42
43
  "devDependencies": {
43
- "@clappr/core": "^0.14.8",
44
+ "@clappr/core": "^0.16.0",
44
45
  "@rollup/plugin-replace": "^2.4.2",
45
- "hls.js": "1.6.16",
46
+ "hls.js": "~1.6.17",
46
47
  "rollup-plugin-filesize": "^9.1.1",
47
48
  "rollup-plugin-serve": "^1.1.0"
48
49
  }
@@ -4,19 +4,25 @@
4
4
  */
5
5
  const fs = require('fs')
6
6
  const path = require('path')
7
+ const vm = require('vm')
8
+ const { TextEncoder, TextDecoder } = require('util')
9
+
10
+ // jest-environment-jsdom omits these; must run before the require below —
11
+ // jsdom's whatwg-url throws on load without TextEncoder/TextDecoder.
12
+ global.TextEncoder = global.TextEncoder || TextEncoder
13
+ global.TextDecoder = global.TextDecoder || TextDecoder
14
+ const { JSDOM } = require('jsdom')
15
+ const { expectNoNativeClasses } = require('../../../test/dist-contract')
7
16
 
8
17
  const DIST = path.join(__dirname, '..', 'dist')
9
18
 
10
19
  const ARTIFACTS = {
11
20
  main: 'hlsjs-playback.js',
12
21
  mainMin: 'hlsjs-playback.min.js',
13
- external: 'hlsjs-playback.external.js',
14
- externalMin: 'hlsjs-playback.external.min.js',
15
22
  esm: 'hlsjs-playback.esm.js'
16
23
  }
17
24
 
18
- const EMBEDS_HLS = [ARTIFACTS.main, ARTIFACTS.mainMin, ARTIFACTS.esm]
19
- const EXTERNAL_HLS = [ARTIFACTS.external, ARTIFACTS.externalMin]
25
+ const UMD_ARTIFACTS = [ARTIFACTS.main, ARTIFACTS.mainMin]
20
26
 
21
27
  function readArtifact(name) {
22
28
  return fs.readFileSync(path.join(DIST, name), 'utf8')
@@ -27,11 +33,30 @@ function loadArtifact(name) {
27
33
  return require(path.join(DIST, name))
28
34
  }
29
35
 
36
+ function resolvePlayback(HlsjsPlaybackExport) {
37
+ return HlsjsPlaybackExport.default || HlsjsPlaybackExport
38
+ }
39
+
40
+ function loadUmdInSandbox(filename, { hls } = {}) {
41
+ const code = readArtifact(filename)
42
+ const dom = new JSDOM('<!doctype html><html><body></body></html>', {
43
+ url: 'http://localhost/',
44
+ pretendToBeVisual: true,
45
+ runScripts: 'outside-only'
46
+ })
47
+ const sandbox = dom.getInternalVMContext()
48
+ sandbox.Clappr = require('@clappr/core')
49
+ if (hls !== undefined) sandbox.Hls = hls
50
+
51
+ vm.runInContext(code, sandbox, { filename: path.join(DIST, filename) })
52
+ return sandbox
53
+ }
54
+
30
55
  function assertPlaybackContract(HlsjsPlaybackExport) {
31
56
  // Must re-require after resetModules so the prototype identity matches the
32
57
  // @clappr/core instance the artifact just resolved.
33
58
  const { HTML5Video } = require('@clappr/core')
34
- const Playback = HlsjsPlaybackExport.default || HlsjsPlaybackExport
59
+ const Playback = resolvePlayback(HlsjsPlaybackExport)
35
60
 
36
61
  expect(typeof Playback).toBe('function')
37
62
  expect(Object.getPrototypeOf(Playback.prototype)).toBe(HTML5Video.prototype)
@@ -54,31 +79,13 @@ function assertPlaybackContract(HlsjsPlaybackExport) {
54
79
  playback.destroy()
55
80
  }
56
81
 
57
- function assertDoesNotEmbedCore(source) {
58
- // Same failure mode as the pre-fix min.js shipping a full Clappr + Zepto copy.
59
- expect(source).not.toMatch(/\bZepto\b/)
60
- expect(source).not.toContain('clappr-core')
61
- expect(source).not.toContain('@clappr/zepto')
62
- }
63
-
64
- function assertDoesNotEmbedHls(source) {
65
- expect(source).toMatch(/['"]hls\.js['"]/)
66
- // External builds are ~14–31 KB; 100 KB leaves headroom without matching the
67
- // ~500 KB+ hls.js-embedded family.
68
- expect(source.length).toBeLessThan(100000)
82
+ function assertSourceMappingURL(filename) {
83
+ expect(readArtifact(filename)).toContain(`sourceMappingURL=${filename}.map`)
69
84
  }
70
85
 
71
- function assertEmbedsHls(source) {
72
- // Keep until #2538 inverts the default layout — flip deliberately then.
73
- expect(source).not.toMatch(/require\(['"]hls\.js['"]\)/)
74
- expect(source.length).toBeGreaterThan(100000)
75
- }
76
-
77
- function assertSourceMap(filename) {
78
- const mapName = `${filename}.map`
79
- expect(fs.existsSync(path.join(DIST, mapName))).toBe(true)
80
- expect(readArtifact(filename)).toContain(`sourceMappingURL=${mapName}`)
81
- }
86
+ const EXPECTED_SOURCEMAPS = Object.values(ARTIFACTS)
87
+ .map(filename => `${filename}.map`)
88
+ .sort()
82
89
 
83
90
  afterEach(() => {
84
91
  jest.restoreAllMocks()
@@ -87,29 +94,48 @@ afterEach(() => {
87
94
  describe.each([
88
95
  ['main UMD', ARTIFACTS.main],
89
96
  ['main UMD minified', ARTIFACTS.mainMin],
90
- ['external UMD', ARTIFACTS.external],
91
- ['external UMD minified', ARTIFACTS.externalMin],
92
97
  ['ESM', ARTIFACTS.esm]
93
98
  ])('%s (%s)', (_label, filename) => {
94
99
  test('exports a HlsjsPlayback class that extends HTML5Video and exposes HLSJS', () => {
95
100
  assertPlaybackContract(loadArtifact(filename))
96
101
  })
97
102
 
98
- test('does not embed @clappr/core or Zepto', () => {
99
- assertDoesNotEmbedCore(readArtifact(filename))
103
+ test('publishes a sourcemap comment', () => {
104
+ assertSourceMappingURL(filename)
105
+ })
106
+
107
+ test('does not emit native class syntax', () => {
108
+ expectNoNativeClasses(readArtifact(filename))
100
109
  })
110
+ })
111
+
112
+ describe('dist sourcemap inventory', () => {
113
+ test('ships exactly the expected .map files', () => {
114
+ const maps = fs
115
+ .readdirSync(DIST)
116
+ .filter(f => f.endsWith('.map'))
117
+ .sort()
118
+ expect(maps).toEqual(EXPECTED_SOURCEMAPS)
119
+ })
120
+ })
101
121
 
102
- test('publishes a sourcemap', () => {
103
- assertSourceMap(filename)
122
+ describe('hls.js peer identity', () => {
123
+ test.each(Object.values(ARTIFACTS))('%s defers to the consumer hls.js', filename => {
124
+ const Playback = resolvePlayback(loadArtifact(filename))
125
+ expect(Playback.HLSJS).toBe(require('hls.js'))
104
126
  })
105
127
  })
106
128
 
107
- describe('hls.js embedding contract', () => {
108
- test.each(EXTERNAL_HLS)('%s does not embed hls.js', filename => {
109
- assertDoesNotEmbedHls(readArtifact(filename))
129
+ describe('UMD global.Hls branch', () => {
130
+ test.each(UMD_ARTIFACTS)('%s resolves HLSJS from window.Hls', filename => {
131
+ const hls = require('hls.js')
132
+ const sandbox = loadUmdInSandbox(filename, { hls })
133
+ expect(sandbox.HlsjsPlayback.HLSJS).toBe(hls)
110
134
  })
111
135
 
112
- test.each(EMBEDS_HLS)('%s embeds hls.js', filename => {
113
- assertEmbedsHls(readArtifact(filename))
136
+ test.each(UMD_ARTIFACTS)('%s throws a clear error when window.Hls is missing', filename => {
137
+ expect(() => loadUmdInSandbox(filename)).toThrow(
138
+ '@clappr/hlsjs-playback requires hls.js (^1) to be loaded before it'
139
+ )
114
140
  })
115
141
  })
package/src/hls.js CHANGED
@@ -5,6 +5,10 @@
5
5
  import { Events, HTML5Video, Log, Playback, PlayerError, Utils } from '@clappr/core'
6
6
  import HLSJS from 'hls.js'
7
7
 
8
+ if (!HLSJS) {
9
+ throw new Error('@clappr/hlsjs-playback requires hls.js (^1) to be loaded before it')
10
+ }
11
+
8
12
  const { now, listContainsIgnoreCase } = Utils
9
13
  const AUTO = -1
10
14
  const DEFAULT_RECOVER_ATTEMPTS = 16
@@ -213,7 +217,7 @@ export default class HlsjsPlayback extends HTML5Video {
213
217
  this._segmentTargetDuration = null
214
218
  // #EXT-X-PLAYLIST-TYPE
215
219
  this._playlistType = null
216
- this._recoverAttemptsRemaining = this.options.hlsRecoverAttempts || DEFAULT_RECOVER_ATTEMPTS
220
+ this._recoverAttemptsRemaining = this.options.hlsRecoverAttempts ?? DEFAULT_RECOVER_ATTEMPTS
217
221
  }
218
222
 
219
223
  _setup() {
@@ -372,8 +376,7 @@ export default class HlsjsPlayback extends HTML5Video {
372
376
  }
373
377
 
374
378
  seekPercentage(percentage) {
375
- const seekTo = percentage > 0 ? this._duration * (percentage / 100) : this._duration
376
- this.seek(seekTo)
379
+ this.seek(this._duration * (percentage / 100))
377
380
  }
378
381
 
379
382
  seek(time) {