From 8f7eeea5bf4c193f2fb47ea2ec8660f40b180264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20Moska=C5=82a?= Date: Wed, 25 Mar 2026 15:51:34 +0100 Subject: [PATCH] feat(example): web --- example/index.web.js | 8 ++ example/package.json | 17 +++- example/web/index.html | 16 ++++ example/web/webpack.config.js | 85 +++++++++++++++++++ .../src/core/video-view/VideoView.web.tsx | 1 + 5 files changed, 125 insertions(+), 2 deletions(-) create mode 100644 example/index.web.js create mode 100644 example/web/index.html create mode 100644 example/web/webpack.config.js diff --git a/example/index.web.js b/example/index.web.js new file mode 100644 index 00000000..f4124016 --- /dev/null +++ b/example/index.web.js @@ -0,0 +1,8 @@ +import { AppRegistry } from 'react-native'; +import { name as appName } from './app.json'; +import App from './src/App'; + +AppRegistry.registerComponent(appName, () => App); +AppRegistry.runApplication(appName, { + rootTag: document.getElementById('root'), +}); diff --git a/example/package.json b/example/package.json index 4e12fd24..3fa135dc 100644 --- a/example/package.json +++ b/example/package.json @@ -9,12 +9,16 @@ "typecheck": "tsc", "start": "react-native start --client-logs", "bundle-install": "bundle install", - "pods": "cd ios && pod install && cd .." + "pods": "cd ios && pod install && cd ..", + "web": "webpack serve --mode development --config web/webpack.config.js", + "build:web": "webpack --mode production --config web/webpack.config.js" }, "dependencies": { "@react-native-community/slider": "^4.5.6", "react": "18.3.1", + "react-dom": "18.3.1", "react-native": "^0.77.0", + "react-native-web": "^0.19.13", "react-native-nitro-modules": "0.35.0", "react-native-video": "*", "@react-native-video/drm": "*" @@ -33,7 +37,16 @@ "@types/react": "^18.2.44", "eslint": "^8.51.0", "prettier": "^3.0.3", - "typescript": "^5.2.2" + "typescript": "^5.2.2", + "webpack": "^5.97.0", + "webpack-cli": "^6.0.0", + "webpack-dev-server": "^5.2.0", + "babel-loader": "^9.2.1", + "babel-plugin-react-native-web": "^0.19.13", + "url-loader": "^4.1.1", + "html-webpack-plugin": "^5.6.3", + "style-loader": "^4.0.0", + "css-loader": "^7.1.2" }, "engines": { "node": ">=18" diff --git a/example/web/index.html b/example/web/index.html new file mode 100644 index 00000000..ec654c90 --- /dev/null +++ b/example/web/index.html @@ -0,0 +1,16 @@ + + + + + + React Native Video - Example + + + +
+ + diff --git a/example/web/webpack.config.js b/example/web/webpack.config.js new file mode 100644 index 00000000..d56a155c --- /dev/null +++ b/example/web/webpack.config.js @@ -0,0 +1,85 @@ +const path = require('path'); +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +const appDirectory = path.resolve(__dirname, '../'); +const rootDirectory = path.resolve(__dirname, '../../'); + +const babelLoaderConfiguration = { + test: /\.(js|jsx|ts|tsx)$/, + include: [ + path.resolve(appDirectory, 'index.web.js'), + path.resolve(appDirectory, 'src'), + // Monorepo packages that need transpiling + path.resolve(rootDirectory, 'packages/react-native-video/src'), + ], + use: { + loader: 'babel-loader', + options: { + cacheDirectory: true, + presets: [ + '@babel/preset-env', + ['@babel/preset-react', { runtime: 'automatic' }], + '@babel/preset-typescript', + ], + plugins: ['react-native-web'], + }, + }, +}; + +const imageLoaderConfiguration = { + test: /\.(gif|jpe?g|png|svg)$/, + use: { + loader: 'url-loader', + options: { name: '[name].[ext]' }, + }, +}; + +const cssLoaderConfiguration = { + test: /\.css$/, + use: ['style-loader', 'css-loader'], +}; + +module.exports = { + entry: path.resolve(appDirectory, 'index.web.js'), + output: { + filename: 'bundle.web.js', + path: path.resolve(appDirectory, 'dist'), + }, + module: { + rules: [ + babelLoaderConfiguration, + imageLoaderConfiguration, + cssLoaderConfiguration, + ], + }, + resolve: { + alias: { + 'react-native$': 'react-native-web', + // Native-only modules that should not be bundled on web + 'react-native-nitro-modules': false, + '@react-native-video/drm': false, + // Resolve react-native-video from source (not lib/) for web + 'react-native-video': path.resolve(rootDirectory, 'packages/react-native-video/src'), + }, + extensions: [ + '.web.tsx', '.web.ts', '.web.js', + '.tsx', '.ts', '.js', '.jsx', '.json', + ], + // Monorepo: resolve packages from both example and root node_modules + modules: [ + path.resolve(appDirectory, 'node_modules'), + path.resolve(rootDirectory, 'node_modules'), + 'node_modules', + ], + }, + plugins: [ + new HtmlWebpackPlugin({ + template: path.resolve(appDirectory, 'web/index.html'), + }), + ], + devServer: { + static: path.resolve(appDirectory, 'dist'), + hot: true, + port: 8080, + }, +}; diff --git a/packages/react-native-video/src/core/video-view/VideoView.web.tsx b/packages/react-native-video/src/core/video-view/VideoView.web.tsx index 9fb5a020..26544c25 100644 --- a/packages/react-native-video/src/core/video-view/VideoView.web.tsx +++ b/packages/react-native-video/src/core/video-view/VideoView.web.tsx @@ -13,6 +13,7 @@ import type { ListenerSubscription } from "../types/EventEmitter"; import type { VideoViewProps, VideoViewRef } from "./VideoViewProps"; import { createPlayer, videoFeatures, usePlayerContext, useMediaAttach } from "@videojs/react"; import { VideoSkin } from "@videojs/react/video"; +import "@videojs/react/video/skin.css"; const Player = createPlayer({ features: videoFeatures });