基础
概念 | webpack 中文文档 | webpack 中文文档 | webpack 中文网
Introduction to React Native for Web // React Native for Web
Webpack 是一个现代的 JavaScript 应用程序的静态模块打包工具,它将应用程序所依赖的各种资源(js、css、图片等)视为模块,通过 loader 转换这些模块,最后打包成符合生产环境部署的静态资源。
Webpack 的运行机制基于一条简单的原则:一切文件皆模块。因此,Webpack 在构建应用程序时,会先从入口模块开始递归解析模块依赖,然后通过 loader 处理各种类型的模块,最后打包成一个或多个浏览器可识别的静态资源。
Webpack 的基本配置包括 entry、output、module 和 plugins 四个部分。其中,entry 指定了入口模块,output 指定了输出目录和输出文件名,module 则用于配置 loader 和其他的一些规则,plugins 则是用于扩展 Webpack 功能的插件。
在使用 Webpack 进行项目开发时,我们通常需要使用 Babel 将 ES6+ 代码转换成浏览器兼容的 ES5 代码。Babel 的作用是将 JavaScript 新特性转换成浏览器支持的语法,例如箭头函数、解构赋值等。而 Loader 则是 Webpack 中用于处理各种类型文件的工具,例如将 css 转换成 JavaScript 对象、将图片转换成 data URL 等。
Babel是一个JavaScript编译器,可以将最新版本的JavaScript转换为向后兼容的代码,以便在旧版浏览器或其他环境中运行。Babel的作用是让我们使用最新的JavaScript语法特性,而不必担心浏览器是否支持这些特性。
过程
yarn add react-dom react-native-web
yarn add react-native-reanimated
yarn add -D babel-plugin-react-native-web
yarn add -D babel-loader url-loader webpack webpack-cli webpack-dev-server
yarn add -D babel-plugin-react-native-web
#每次打包发布时自动清理掉 dist 目录中的旧文件,
yarn add -D clean-webpack-plugin
#html-webpack-plugin的主要作用就是在webpack构建后生成html文件,同时把构建好入口js文件引入到生成的html文件中。
yarn add -D html-webpack-plugin
webpack.config.js
const path = require('path');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const appDirectory = path.resolve(__dirname);
// const {presets} = require(`${appDirectory}/babel.config.js`);
const compileNodeModules = [
// Add every react-native package that needs compiling
// 'react-native-gesture-handler',
].map((moduleName) => path.resolve(appDirectory, `node_modules/${moduleName}`));
const baseProjectSource = [
path.resolve(appDirectory, 'web/index.web.js'), // Entry to your application
path.resolve(appDirectory, 'web/App.web.js'), // Change this to your main App file
path.resolve(appDirectory, './src'),
];
const babelLoaderConfiguration = {
test: /\.(js|jsx|ts|tsx)$/,
// Add every directory that needs to be compiled by Babel during the build.
include: baseProjectSource,
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
// The 'react-native' preset is recommended to match React Native's packager
presets: ['module:metro-react-native-babel-preset'],
// Re-write paths to import only the modules needed by the app
plugins: ['react-native-web', 'react-native-reanimated/plugin'],
},
},
};
const imageLoaderConfiguration = {
test: /\.(gif|jpe?g|png)$/,
use: {
loader: 'url-loader',
options: {
name: '[name].[ext]',
},
},
};
module.exports = {
entry: {
app: path.join(appDirectory, 'web/index.web.js'),
},
output: {
path: path.resolve(appDirectory, 'dist'),
publicPath: '/',
filename: 'upup.bundle.js',
},
resolve: {
// If you're working on a multi-platform React Native app, web-specific
// module implementations should be written in files using the extension
// `.web.js`.
extensions: ['.web.tsx', '.web.ts', '.tsx', '.ts', '.web.js', '.js'],
alias: {
'react-native$': 'react-native-web',
},
},
module: {
rules: [
babelLoaderConfiguration,
imageLoaderConfiguration,
],
},
devServer: {
port: 8080,
historyApiFallback: true,
open: !process.env.CI,
},
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: [
'**/*'
]
}),
// `process.env.NODE_ENV === 'production'` must be `true` for production
// builds to eliminate development checks and reduce build size. You may
// wish to include additional optimizations.
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
__DEV__: process.env.NODE_ENV === 'production' || true
}),
new HtmlWebpackPlugin({
template: path.join(appDirectory, 'web/index.html'),
}),
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({
// See: https://github.com/necolas/react-native-web/issues/349
__DEV__: JSON.stringify(true),
}),
],
};
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>RN Web</title>
<style>
#app-root {
display: flex;
flex: 1 1 100%;
height: 100vh;
}
</style>
</head>
<body>
<div id="app-root"></div>
</body>
</html>
index.web.js
import {AppRegistry} from 'react-native';
import appInfo from '../app.json';
import App from './App.web';
AppRegistry.registerComponent(appInfo.name, () => App);
AppRegistry.runApplication(appInfo.name, {
initialProps: {},
rootTag: document.getElementById('app-root'),
});
App.web.js
import React from 'react';
import FaqTestnet from '../src/screen/FaqTestnet';
import AboutTestnet from '../src/screen/AboutTestnet';
import 'react-native-gesture-handler';
import {NavigationContainer} from '@react-navigation/native';
import {
createStackNavigator,
CardStyleInterpolators,
} from '@react-navigation/stack';
import Color from "../src/app/Color";
import DarkTheme from '../src/app/DarkTheme';
const Stack = createStackNavigator();
const config = {
screens: {
FaqTestnet: 'faqtestnet',
AboutTestnet: 'abouttestnet',
},
};
const linking = {
prefixes: ['http://tokshow.io', 'http://localhost:8080', 'http://127.0.0.1:5500/'],
config,
};
function App() {
return (
<NavigationContainer linking={linking} fallback={<Text>Loading...</Text>} theme={DarkTheme}>
<Stack.Navigator
initialRouteName="AboutTestnet"
screenOptions={{
animationEnabled: false,
headerShown: false,
unmountOnBlur: false,
cardStyleInterpolator: CardStyleInterpolators.forHorizontalIOS,
}}>
<Stack.Screen
name="FaqTestnet"
component={FaqTestnet}
options={{
title: 'Testnet FAQ',
}}
/>
<Stack.Screen
name="AboutTestnet"
component={AboutTestnet}
options={{
title: 'About the Incentivized Testnet',
}}
/>
</Stack.Navigator>
</NavigationContainer>
);
}
export default App;
package.json
"scripts": {
"web:release": "export NODE_ENV=production && rm -rf dist/ && webpack --config ./webpack.config.js",
"web": "export NODE_ENV=development && webpack-dev-server --config ./webpack.config.js",
参考