@quicktvui/web-cli 2.4.2 → 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/README.md CHANGED
@@ -1,8 +1,8 @@
1
- # @quicktvui/web-cli v2
1
+ # @quicktvui/web-cli v3
2
2
 
3
- QuickTVUI Web 开发服务器 CLI 工具,v2 采用委托构建 + Bundle 加载模式。
3
+ QuickTVUI Web 开发服务器 CLI 工具,v3 采用委托构建 + Bundle 加载模式。
4
4
 
5
- ## v2 架构变化
5
+ ## v3 架构说明
6
6
 
7
7
  | 项 | v1 | v2 |
8
8
  |---|---|---|
@@ -16,11 +16,11 @@ QuickTVUI Web 开发服务器 CLI 工具,v2 采用委托构建 + Bundle 加载
16
16
  ## 安装
17
17
 
18
18
  ```bash
19
- npm install @quicktvui/web-cli@2 --save-dev
19
+ npm install @quicktvui/web-cli@3 --save-dev
20
20
  # 或
21
- yarn add @quicktvui/web-cli@2 --dev
21
+ yarn add @quicktvui/web-cli@3 --dev
22
22
  # 或
23
- pnpm add @quicktvui/web-cli@2 -D
23
+ pnpm add @quicktvui/web-cli@3 -D
24
24
  ```
25
25
 
26
26
  ## 前置要求
@@ -63,11 +63,11 @@ npx qt-web-cli
63
63
  -o, --open 自动打开浏览器
64
64
  -h, --help 显示帮助信息
65
65
  -v, --version 显示 CLI 版本
66
- --info 显示 CLI 和 web-renderer 版本
66
+ --info 显示 CLI 和 web-runtime 版本
67
67
  --dev-script <name> 指定要运行的 npm script (默认: dev)
68
68
  --dist-dir <path> 指定构建产物目录 (默认: dist/dev)
69
69
  --no-auto-build 跳过自动调用 dev 脚本,仅启动服务器
70
- --v1 使用 v1 模式 (webpack 自构建,已废弃)
70
+ --v1 已移除,仅保留参数兼容提示
71
71
  ```
72
72
 
73
73
  ### 使用场景
@@ -94,11 +94,11 @@ qt-web-cli --dev-script build
94
94
  # 使用 npm run build 替代 npm run dev
95
95
  ```
96
96
 
97
- #### 4. 使用 v1 模式
97
+ #### 4. `--v1` 兼容提示
98
98
 
99
99
  ```bash
100
100
  qt-web-cli --v1
101
- # 回退到 v1 模式(webpack 自构建),已废弃
101
+ # 提示 v1 已移除,请使用默认 web-runtime 模式
102
102
  ```
103
103
 
104
104
  ## 工作流程
package/bin/qt-web-cli.js CHANGED
@@ -44,31 +44,29 @@ if (args.v || args.version) {
44
44
  process.exit(0)
45
45
  }
46
46
 
47
+ function resolvePackageJson(possiblePaths) {
48
+ for (const pkgPath of possiblePaths) {
49
+ try {
50
+ return require(pkgPath)
51
+ } catch (e) {}
52
+ }
53
+ return null
54
+ }
55
+
47
56
  // 显示详细信息
48
57
  if (args.info) {
49
58
  const cliPkg = require(path.join(__dirname, '../package.json'))
50
59
  console.log(`@quicktvui/web-cli v${cliPkg.version}`)
51
- console.log(` Mode: v2 (delegate build)`)
52
- try {
53
- let rendererPkg
54
- const possiblePaths = [
55
- '@quicktvui/web-renderer/package.json',
56
- path.join(__dirname, '../../web-renderer/package.json'),
57
- path.join(__dirname, '../../../web-renderer/package.json'),
58
- ]
59
- for (const pkgPath of possiblePaths) {
60
- try {
61
- rendererPkg = require(pkgPath)
62
- break
63
- } catch (e) {}
64
- }
65
- if (rendererPkg) {
66
- console.log(`@quicktvui/web-renderer v${rendererPkg.version}`)
67
- } else {
68
- console.log('@quicktvui/web-renderer (not installed)')
69
- }
70
- } catch (e) {
71
- console.log('@quicktvui/web-renderer (not installed)')
60
+ console.log(` Mode: v2 (web-runtime)`)
61
+ const runtimePkg = resolvePackageJson([
62
+ '@quicktvui/web-runtime/package.json',
63
+ path.join(__dirname, '../../web-runtime/package.json'),
64
+ path.join(__dirname, '../../../web-runtime/package.json'),
65
+ ])
66
+ if (runtimePkg) {
67
+ console.log(`@quicktvui/web-runtime v${runtimePkg.version}`)
68
+ } else {
69
+ console.log('@quicktvui/web-runtime (not installed)')
72
70
  }
73
71
  process.exit(0)
74
72
  }
@@ -86,11 +84,11 @@ Options:
86
84
  -o, --open 自动打开浏览器
87
85
  -h, --help 显示帮助信息
88
86
  -v, --version 显示 CLI 版本
89
- --info 显示 CLI 和 web-renderer 版本
87
+ --info 显示 CLI 和 web-runtime 版本
90
88
  --dev-script <name> 指定要运行的 npm script (默认: dev)
91
89
  --dist-dir <path> 指定构建产物目录 (默认: dist/dev)
92
90
  --no-auto-build 跳过自动调用 dev 脚本,仅启动服务器
93
- --v1 使用 v1 模式 (webpack 自构建,已废弃)
91
+ --v1 已移除,仅保留参数兼容提示
94
92
 
95
93
  v2 模式 (默认):
96
94
  自动检测项目的 dev 脚本,调用 npm run dev 构建产物
@@ -98,14 +96,14 @@ v2 模式 (默认):
98
96
  支持热更新 (SSE)
99
97
 
100
98
  v1 模式 (--v1):
101
- 使用内置 webpack 配置自行构建项目 (已废弃)
99
+ 已移除,web-cli 统一走 web-runtime
102
100
 
103
101
  Examples:
104
102
  qt-web-cli # v2 模式,自动构建+启动
105
103
  qt-web-cli --no-auto-build # v2 模式,仅启动服务器(需先手动 npm run dev)
106
104
  qt-web-cli --dev-script build # 使用 build 脚本替代 dev
107
105
  qt-web-cli --port 8080 # 指定端口
108
- qt-web-cli --v1 # 使用 v1 模式
106
+ qt-web-cli --v1 # 提示 v1 已移除
109
107
  `)
110
108
  process.exit(0)
111
109
  }
@@ -117,8 +115,8 @@ Examples:
117
115
  async function main() {
118
116
  // 强制使用 v1 模式
119
117
  if (args.v1) {
120
- signale.warn('v1 模式已废弃,建议迁移到 v2 模式')
121
- return runV1()
118
+ signale.error('v1 模式已移除,请使用默认的 web-runtime 模式')
119
+ process.exit(1)
122
120
  }
123
121
 
124
122
  signale.pending('正在启动 QuickTVUI Web CLI v2 ...')
@@ -144,8 +142,8 @@ async function main() {
144
142
  const distFullPath = path.join(projectRoot, distDir)
145
143
 
146
144
  if (!devScript && !fs.existsSync(distFullPath)) {
147
- signale.warn('项目未配置 dev 脚本且 dist/dev 目录不存在,回退到 v1 模式')
148
- return runV1()
145
+ signale.error('项目未配置 dev 脚本,且 dist/dev 目录不存在,无法启动 web-runtime 模式')
146
+ process.exit(1)
149
147
  }
150
148
 
151
149
  // ============================================================================
@@ -336,127 +334,6 @@ async function main() {
336
334
  process.on('SIGTERM', cleanup)
337
335
  }
338
336
 
339
- // ============================================================================
340
- // v1 模式 (webpack 自构建,已废弃)
341
- // ============================================================================
342
-
343
- function runV1() {
344
- signale.pending('正在启动 QuickTVUI Web CLI v1 (webpack 模式)...')
345
-
346
- // 查找项目根目录
347
- const projectRoot = findProjectRoot()
348
- if (!projectRoot) {
349
- signale.error('无法找到项目根目录')
350
- process.exit(1)
351
- }
352
-
353
- signale.info(`项目根目录: ${projectRoot}`)
354
-
355
- // 读取 package.json
356
- let pkg = {}
357
- try {
358
- pkg = require(path.join(projectRoot, 'package.json'))
359
- } catch (e) {}
360
-
361
- // 检测入口文件
362
- let mainEntry
363
- let entryType
364
-
365
- const entryCandidates = [
366
- { name: 'src/main-native.ts', path: './src/main-native.ts', type: 'package' },
367
- { name: 'src/main-native.js', path: './src/main-native.js', type: 'package' },
368
- { name: 'src/main.ts', path: './src/main.ts', type: 'package' },
369
- { name: 'src/main.js', path: './src/main.js', type: 'package' },
370
- { name: 'main (package.json)', path: pkg.main, type: 'package' },
371
- ]
372
-
373
- for (const candidate of entryCandidates) {
374
- if (!candidate.path) continue
375
- const entryFullPath = path.resolve(projectRoot, candidate.path)
376
- if (fs.existsSync(entryFullPath)) {
377
- mainEntry = candidate.path
378
- entryType = candidate.type
379
- signale.info(`主入口: ${mainEntry}`)
380
- break
381
- }
382
- }
383
-
384
- if (!mainEntry) {
385
- signale.error('无法找到有效的入口文件')
386
- process.exit(1)
387
- }
388
-
389
- const mainEntryPath = path.resolve(projectRoot, mainEntry)
390
-
391
- // 设置环境变量
392
- process.env.NODE_ENV = 'development'
393
- process.env.QUICKTVUI_PROJECT_ROOT = projectRoot
394
- process.env.QUICKTVUI_MAIN_ENTRY = mainEntryPath
395
- process.env.QUICKTVUI_ENTRY_TYPE = entryType
396
- process.env.QUICKTVUI_PORT = String(args.port)
397
-
398
- // 检测 OpenSSL 版本
399
- const needLegacyProvider = checkOpenSSLVersion(process.versions.openssl)
400
- if (needLegacyProvider) {
401
- signale.warn(`检测到 OpenSSL ${process.versions.openssl},已添加 --openssl-legacy-provider`)
402
- process.env.NODE_OPTIONS = '--openssl-legacy-provider'
403
- }
404
-
405
- signale.pending(`启动开发服务器: http://localhost:${args.port}`)
406
-
407
- // 使用 webpack Node API 启动开发服务器
408
- const defaultConfigPath = path.resolve(__dirname, '../lib/webpack.config.js')
409
- const userConfigPath = args.config ? path.resolve(projectRoot, args.config) : null
410
- startDevServer(defaultConfigPath, args.port, args.open, userConfigPath)
411
- }
412
-
413
- /**
414
- * 使用 webpack Node API 启动开发服务器 (v1)
415
- */
416
- function startDevServer(configPath, port, shouldOpen, userConfigPath) {
417
- const webpack = require('webpack')
418
- const WebpackDevServer = require('webpack-dev-server')
419
- const { merge } = require('webpack-merge')
420
-
421
- let config = require(configPath)
422
-
423
- if (userConfigPath) {
424
- if (!fs.existsSync(userConfigPath)) {
425
- signale.error(`自定义配置文件不存在: ${userConfigPath}`)
426
- process.exit(1)
427
- }
428
- signale.info(`加载用户配置: ${userConfigPath}`)
429
- const userConfig = require(userConfigPath)
430
- config = merge(config, userConfig)
431
- }
432
-
433
- config.devServer = config.devServer || {}
434
- config.devServer.port = port
435
- config.devServer.open = false
436
-
437
- const compiler = webpack(config)
438
- const server = new WebpackDevServer(config.devServer, compiler)
439
-
440
- server.startCallback((err) => {
441
- if (err) {
442
- signale.error('启动开发服务器失败:', err.message)
443
- process.exit(1)
444
- }
445
- signale.success(`开发服务器已启动: http://localhost:${port}`)
446
-
447
- if (shouldOpen) {
448
- openBrowser(`http://localhost:${port}`)
449
- }
450
- })
451
-
452
- process.on('SIGINT', () => {
453
- server.stopCallback(() => {
454
- signale.info('开发服务器已停止')
455
- process.exit(0)
456
- })
457
- })
458
- }
459
-
460
337
  // ============================================================================
461
338
  // 工具函数
462
339
  // ============================================================================
@@ -483,13 +360,6 @@ function detectDevScript(pkg, scriptName) {
483
360
  return null
484
361
  }
485
362
 
486
- function checkOpenSSLVersion(version) {
487
- if (!version) return false
488
- const match = /^(\d+)\.(\d+)\.(\d+)/.exec(version)
489
- if (!match) return false
490
- return parseInt(match[1], 10) >= 3
491
- }
492
-
493
363
  function formatSize(bytes) {
494
364
  if (bytes < 1024) return bytes + ' B'
495
365
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'
package/lib/DevServer.js CHANGED
@@ -400,7 +400,7 @@ class DevServer {
400
400
  }
401
401
 
402
402
  // proxy 代理
403
- if (pathname.startsWith('/proxy/')) {
403
+ if (pathname === '/proxy' || pathname.startsWith('/proxy/')) {
404
404
  this._handleProxy(req, res, pathname)
405
405
  return
406
406
  }
@@ -508,27 +508,48 @@ class DevServer {
508
508
  /**
509
509
  * 处理代理请求
510
510
  *
511
- * URL 格式: /proxy/{http|https}/{host}[:port]/{path}[?query]
511
+ * URL 格式:
512
+ * 1. /proxy/{http|https}/{host}[:port]/{path}[?query]
513
+ * 2. /proxy?url={encodeURIComponent(fullUrl)}
512
514
  * 示例:
513
515
  * /proxy/https/api.example.com/v1/data → https://api.example.com/v1/data
514
516
  * /proxy/https/api.example.com:8443/v1/data → https://api.example.com:8443/v1/data
517
+ * /proxy?url=https%3A%2F%2Fapi.example.com%2Fv1%2Fdata → https://api.example.com/v1/data
515
518
  */
516
519
  _handleProxy(req, res, pathname) {
517
- // 从完整 URL 中提取查询参数(pathname 只有路径部分)
518
520
  const fullUrl = url.parse(req.url, true)
519
- const queryString = fullUrl.search || ''
521
+ const rawTargetUrl = fullUrl.query && fullUrl.query.url
522
+
523
+ let protocol
524
+ let hostPort
525
+ let proxyPath
526
+
527
+ if (rawTargetUrl) {
528
+ try {
529
+ const targetUrl = new URL(rawTargetUrl)
530
+ protocol = targetUrl.protocol.replace(':', '')
531
+ hostPort = targetUrl.host
532
+ proxyPath = `${targetUrl.pathname}${targetUrl.search}`
533
+ } catch (e) {
534
+ res.writeHead(400, { 'Content-Type': 'text/plain' })
535
+ res.end('Invalid proxy url query param')
536
+ return
537
+ }
538
+ } else {
539
+ // 从完整 URL 中提取查询参数(pathname 只有路径部分)
540
+ const queryString = fullUrl.search || ''
541
+ const match = pathname.match(/^\/proxy\/(https?)\/([^/]+)(\/.*)?$/)
542
+ if (!match) {
543
+ res.writeHead(400, { 'Content-Type': 'text/plain' })
544
+ res.end('Invalid proxy URL format. Use: /proxy/{http|https}/{host}[:port]/{path}')
545
+ return
546
+ }
520
547
 
521
- const match = pathname.match(/^\/proxy\/(https?)\/([^/]+)(\/.*)?$/)
522
- if (!match) {
523
- res.writeHead(400, { 'Content-Type': 'text/plain' })
524
- res.end('Invalid proxy URL format. Use: /proxy/{http|https}/{host}[:port]/{path}')
525
- return
548
+ protocol = match[1]
549
+ hostPort = match[2]
550
+ proxyPath = (match[3] || '/') + queryString
526
551
  }
527
552
 
528
- const protocol = match[1]
529
- const hostPort = match[2]
530
- const proxyPath = (match[3] || '/') + queryString
531
-
532
553
  // 分离 host 和 port
533
554
  let hostname = hostPort
534
555
  let port = protocol === 'https' ? 443 : 80
@@ -538,17 +559,33 @@ class DevServer {
538
559
  port = parseInt(parts[1], 10) || port
539
560
  }
540
561
 
541
- // 过滤掉 hop-by-hop 头,避免转发问题
542
- const headers = { ...req.headers }
543
- delete headers['host']
544
- delete headers['connection']
545
- delete headers['keep-alive']
546
- delete headers['transfer-encoding']
547
- delete headers['te']
548
- delete headers['trailer']
549
- delete headers['upgrade']
550
- delete headers['proxy-connection']
551
- headers['host'] = hostPort
562
+ // console.log('[Proxy] incoming request:', {
563
+ // method: req.method,
564
+ // requestUrl: req.url,
565
+ // target: `${protocol}://${hostPort}${proxyPath}`,
566
+ // range: req.headers && req.headers.range,
567
+ // })
568
+
569
+ // Media/file download proxy should forward a minimal header set.
570
+ // Forwarding browser-only headers (origin, referer, sec-fetch-*, cookies)
571
+ // can cause some signed upstream URLs to be rejected with 400.
572
+ const headers = {
573
+ host: hostPort,
574
+ 'user-agent': req.headers['user-agent'] || 'Mozilla/5.0',
575
+ accept: req.headers.accept || '*/*',
576
+ }
577
+ if (req.headers.range) {
578
+ headers.range = req.headers.range
579
+ }
580
+ if (req.headers['if-range']) {
581
+ headers['if-range'] = req.headers['if-range']
582
+ }
583
+ if (req.headers['if-none-match']) {
584
+ headers['if-none-match'] = req.headers['if-none-match']
585
+ }
586
+ if (req.headers['if-modified-since']) {
587
+ headers['if-modified-since'] = req.headers['if-modified-since']
588
+ }
552
589
  // 标记请求来自代理(方便调试)
553
590
  headers['x-forwarded-for'] = req.socket.remoteAddress
554
591
  headers['x-forwarded-proto'] = protocol
@@ -564,6 +601,14 @@ class DevServer {
564
601
 
565
602
  const httpModule = protocol === 'https' ? require('https') : require('http')
566
603
  const proxyReq = httpModule.request(options, (proxyRes) => {
604
+ // console.log('[Proxy] upstream response:', {
605
+ // method: req.method,
606
+ // requestUrl: req.url,
607
+ // target: `${protocol}://${hostPort}${proxyPath}`,
608
+ // statusCode: proxyRes.statusCode,
609
+ // contentType: proxyRes.headers['content-type'],
610
+ // contentRange: proxyRes.headers['content-range'],
611
+ // })
567
612
  // 代理响应添加 CORS 头
568
613
  const responseHeaders = { ...proxyRes.headers }
569
614
  responseHeaders['access-control-allow-origin'] = this.corsOrigin
@@ -660,6 +705,7 @@ class DevServer {
660
705
  c.style.visibility = 'visible';
661
706
  }
662
707
  }
708
+
663
709
  scaleApp();
664
710
  window.addEventListener('resize', scaleApp);
665
711
  </script>
@@ -1,74 +1,7 @@
1
- // @quicktvui/web-cli - web entry
2
- // 通过 @quicktvui/web-renderer 导入所有依赖
3
- // 动态加载主入口,确保初始化顺序正确
1
+ // Legacy v1 browser entry.
2
+ // web-cli now serves web-runtime and lets web-runtime own the renderer bootstrap.
3
+ // This stub intentionally avoids importing web-renderer directly.
4
4
 
5
- console.log('[Web Renderer] === Starting initialization ===')
6
-
7
- import {
8
- initAsyncLocalStorage,
9
- initAutoProxy,
10
- setupSceneBuilder,
11
- createWebEngine,
12
- applyAllPatches,
13
- TVFocusManager,
14
- startWebEngine,
15
- APP_NAME,
16
- IJKPlayerComponent,
17
- } from '@quicktvui/web-renderer'
18
- import { setupGlobalErrorHandler } from './error-badge.js'
19
-
20
- // 初始化 async localStorage
21
- initAsyncLocalStorage()
22
-
23
- // 初始化自动代理
24
- initAutoProxy()
25
-
26
- // 注册 IJKPlayerComponent
27
- global.__WEB_COMPONENTS__ = global.__WEB_COMPONENTS__ || {}
28
- global.__WEB_COMPONENTS__['IJKPlayerComponent'] = IJKPlayerComponent
29
-
30
- // 设置 SceneBuilder
31
- setupSceneBuilder()
32
-
33
- // 创建 Web 引擎
34
- const engine = createWebEngine()
35
-
36
- // 应用所有补丁
37
- applyAllPatches(engine)
38
-
39
- // 初始化 TV 焦点管理器
40
- global.__TV_FOCUS_MANAGER__ = new TVFocusManager()
41
- console.log('[Web Renderer] TVFocusManager initialized')
42
-
43
- // 初始化错误提示组件(在 DOM 准备好后)
44
- if (document.readyState === 'loading') {
45
- document.addEventListener('DOMContentLoaded', () => setupGlobalErrorHandler())
46
- } else {
47
- setupGlobalErrorHandler()
48
- }
49
- console.log('[Web Renderer] Error badge initialized')
50
-
51
- // 注入全局 CSS
52
- const styleEl = document.createElement('style')
53
- styleEl.id = 'web-platform-reset'
54
- styleEl.textContent = `
55
- #app, #app * { align-items: flex-start; }
56
- [style*="align-items"] { align-items: var(--align-items, center) !important; }
57
- `
58
- document.head.appendChild(styleEl)
59
- console.log('[Web Renderer] Global CSS reset injected')
60
-
61
- // 动态加载主入口,等待加载完成后再启动引擎
62
- console.log('[Web Renderer] Importing main module...')
63
- import(__QUICKTVUI_MAIN_ENTRY__)
64
- .then(() => {
65
- console.log('[Web Renderer] Main module loaded')
66
- console.log('[Web Renderer] Starting engine...')
67
- startWebEngine(engine, APP_NAME)
68
- setTimeout(() => {
69
- console.log('[Web Renderer] === Initialization complete ===')
70
- }, 1000)
71
- })
72
- .catch((err) => {
73
- console.error('[Web Renderer] Failed to load main module:', err)
74
- })
5
+ throw new Error(
6
+ '[web-cli] v1 mode has been removed. Use the default web-runtime based flow instead of direct web-renderer bootstrap.'
7
+ )
package/lib/index.js CHANGED
@@ -74,16 +74,6 @@ function detectDevBundle(projectRoot) {
74
74
  * 检测 web renderer 类型(v1 兼容)
75
75
  */
76
76
  function detectWebRendererType(projectRoot) {
77
- if (fs.existsSync(path.join(projectRoot, 'src/web/index.js'))) {
78
- return 'local'
79
- }
80
- try {
81
- const projectPkg = require(path.join(projectRoot, 'package.json'))
82
- const deps = { ...projectPkg?.dependencies, ...projectPkg?.devDependencies }
83
- if (deps['@quicktvui/web-renderer']) {
84
- return 'package'
85
- }
86
- } catch (e) {}
87
77
  return 'package'
88
78
  }
89
79
 
@@ -162,6 +162,14 @@ module.exports = {
162
162
  changeOrigin: true,
163
163
  secure: false,
164
164
  router: (req) => {
165
+ try {
166
+ const requestUrl = new URL(req.url, 'http://localhost')
167
+ const rawUrl = requestUrl.searchParams.get('url')
168
+ if (rawUrl) {
169
+ const targetUrl = new URL(rawUrl)
170
+ return `${targetUrl.protocol}//${targetUrl.host}`
171
+ }
172
+ } catch (e) {}
165
173
  const match = req.url.match(/^\/proxy\/(https?)\/([^/]+)(\/.*)?$/)
166
174
  if (match) {
167
175
  return `${match[1]}://${match[2]}`
@@ -169,6 +177,14 @@ module.exports = {
169
177
  return 'http://placeholder'
170
178
  },
171
179
  pathRewrite: (path, req) => {
180
+ try {
181
+ const requestUrl = new URL(path, 'http://localhost')
182
+ const rawUrl = requestUrl.searchParams.get('url')
183
+ if (rawUrl) {
184
+ const targetUrl = new URL(rawUrl)
185
+ return `${targetUrl.pathname}${targetUrl.search}`
186
+ }
187
+ } catch (e) {}
172
188
  const match = path.match(/^\/proxy\/(https?)\/[^/]+(\/.*)?$/)
173
189
  if (match) {
174
190
  return match[2] || '/'
@@ -257,6 +273,9 @@ module.exports = {
257
273
  {
258
274
  test: /\.js$/,
259
275
  exclude: /node_modules/,
276
+ resolve: {
277
+ fullySpecified: false,
278
+ },
260
279
  use: [
261
280
  {
262
281
  loader: 'babel-loader',
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@quicktvui/web-cli",
3
- "version": "2.4.2",
4
- "description": "CLI tool for QuickTVUI web development v2 - delegate build & bundle loading",
3
+ "version": "3.0.0",
4
+ "description": "CLI tool for QuickTVUI web development v3 - delegate build & bundle loading",
5
5
  "author": "QuickTVUI Team",
6
6
  "license": "Apache-2.0",
7
7
  "bin": {