首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >响应本地Web工具SSR

响应本地Web工具SSR
EN

Stack Overflow用户
提问于 2022-04-28 08:56:07
回答 1查看 114关注 0票数 1

https://necolas.github.io/react-native-web/docs/rendering/

在阅读了文档中的SSR示例之后,我仍然不知道如何实现SSR

我不想在其他框架(如NextJS )中应用SSR

有人能给我举个例子或者给我一些建议吗?

EN

回答 1

Stack Overflow用户

发布于 2022-12-01 18:03:54

我发布这篇文章,并不是为了直接回答最初的问题,因为它是直接针对NextJS的,OP需要独立于NextJS之类的框架。然而,用NextJS理解它可以让任何人更接近事物,因为它们依赖于Webpack配置,NextJS在封装配置中也使用这种配置。

首先要知道的是,一旦为Reacti原住民编写了一个包,它需要首先被转换,以便能够在网络上使用,与webpack config.externals一起使用。

代码语言:javascript
复制
let modulesToTranspile = [
  'react-native',
  'react-native-dotenv',
  'react-native-linear-gradient',
  'react-native-media-query',
  'react-native-paper',
  'react-native-view-more-text',
  // 'react-native-vector-icons',
];

然后,您需要将一些react本地包化名为react本机web等效于让包使用web版本的模块,如:

代码语言:javascript
复制
config.resolve.alias = {
  ...(config.resolve.alias || {}),
  // Transform all direct `react-native` imports to `react-native-web`
  'react-native$': 'react-native-web',
  'react-native-linear-gradient': 'react-native-web-linear-gradient',
};

在这一点上,你几乎得到了本质。其余的是正常Webpack配置的正常应用程序。此外,它还需要本机配置文件中的一些附加配置。我会张贴所有的吐露内容。

对于NextJS:next.config.js

代码语言:javascript
复制
const path = require('path');

let modulesToTranspile = [
  'react-native',
  'react-native-dotenv',
  'react-native-linear-gradient',
  'react-native-media-query',
  'react-native-paper',
  'react-native-view-more-text',
  // 'react-native-vector-icons',
];

// console.log('modules to transpile', modulesToTranspile);

// import ntm = from 'next-transpile-modules';
// const withTM = ntm(modulesToTranspile);
// logic below for externals has been extracted from 'next-transpile-modules'
// we won't use this modules as they don't allow package without 'main' field...
// https://github.com/martpie/next-transpile-modules/issues/170
const getPackageRootDirectory = m =>
  path.resolve(path.join(__dirname, 'node_modules', m));

const modulesPaths = modulesToTranspile.map(getPackageRootDirectory);

const hasInclude = (context, request) => {
  return modulesPaths.some(mod => {
    // If we the code requires/import an absolute path
    if (!request.startsWith('.')) {
      try {
        const moduleDirectory = getPackageRootDirectory(request);
        if (!moduleDirectory) {
          return false;
        }
        return moduleDirectory.includes(mod);
      } catch (err) {
        return false;
      }
    }
    // Otherwise, for relative imports
    return path.resolve(context, request).includes(mod);
  });
};

const configuration = {
  node: {
    global: true,
  },
  env: {
    ENV: process.env.NODE_ENV,
  },
  // optimizeFonts: false,
  // target: 'serverless',

  // bs-platform
  // pageExtensions: ['jsx', 'js', 'bs.js'],

  // options: { buildId, dev, isServer, defaultLoaders, webpack }
  webpack: (config, options) => {
    // config.experimental.forceSwcTransforms = true;

    // console.log('fallback', config.resolve.fallback);
    if (!options.isServer) {
      // We shim fs for things like the blog slugs component
      // where we need fs access in the server-side part
      config.resolve.fallback.fs = false;
    } else {
      // SSR
      // provide plugin
      config.plugins.push(
        new options.webpack.ProvidePlugin({
          requestAnimationFrame: path.resolve(__dirname, './polyfills/raf.js'),
        }),
      );
    }

    // react-native-web
    config.resolve.alias = {
      ...(config.resolve.alias || {}),
      // Transform all direct `react-native` imports to `react-native-web`
      'react-native$': 'react-native-web',
      'react-native-linear-gradient': 'react-native-web-linear-gradient',
    };
    config.resolve.extensions = [
      '.web.js',
      '.web.ts',
      '.web.tsx',
      ...config.resolve.extensions,
    ];

    config.externals = config.externals.map(external => {
      if (typeof external !== 'function') {
        return external;
      }
      return async ({ context, request, getResolve }) => {
        if (hasInclude(context, request)) {
          return;
        }
        return external({ context, request, getResolve });
      };
    });

    const babelLoaderConfiguration = {
      test: /\.jsx?$/,
      use: options.defaultLoaders.babel,
      include: modulesPaths,
      // exclude: /node_modules[/\\](?!react-native-vector-icons)/,
    };

    babelLoaderConfiguration.use.options = {
      ...babelLoaderConfiguration.use.options,
      cacheDirectory: false,
      // For Next JS transpile
      presets: ['next/babel'],
      plugins: [
        ['react-native-web', { commonjs: true }],
        ['@babel/plugin-proposal-class-properties'],
        // ['@babel/plugin-proposal-object-rest-spread'],
      ],
    };

    config.module.rules.push(babelLoaderConfiguration);

    return config;
  },
};

// module.exports = withTM(config);
module.exports = configuration;

当服务器端缺少一些功能时,SSR将无法构建。React最受欢迎的是requestAnimationFrame。我添加了一个Webpack插件来模仿它。它可以是一个空函数或多填充:

文件'polyfills/raf.js(I just put it assetImmediate`):

代码语言:javascript
复制
const polys = { requestAnimationFrame: setImmediate };

module.exports = polys.requestAnimationFrame;

Babel配置对于它的最后一部分是必要的,无法在下一个配置中直接工作。babel.config.js

代码语言:javascript
复制
module.exports = {
  presets: ['module:metro-react-native-babel-preset'],
  plugins: [['module:react-native-dotenv'], 'react-native-reanimated/plugin'],
};

最后,我在package.json中列出的包列表

代码语言:javascript
复制
{
  "name": "my-app",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "android:dev": "adb reverse tcp:8081 tcp:8081 && react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint .",
    "web": "webpack serve -d source-map --mode development --config \"./web/webpack.config.js\" --inline --color --hot",
    "build:web": "webpack --mode production --config \"./web/webpack.config.js\" --hot",
    "next:dev": "next",
    "next:build": "next build",
    "next:start": "next start",
    "next:analyze": "ANALYZE=true next build"
  },
  "dependencies": {
    "@material-ui/core": "^4.12.4",
    "@react-native-async-storage/async-storage": "^1.17.3",
    "@react-navigation/drawer": "^6.4.1",
    "@react-navigation/native": "^6.0.10",
    "@react-navigation/stack": "^6.2.1",
    "@reduxjs/toolkit": "^1.8.1",
    "axios": "^0.21.1",
    "local-storage": "^2.0.0",
    "lottie-ios": "^3.2.3",
    "lottie-react-native": "^5.1.3",
    "lottie-web": "^5.9.4",
    "moment": "^2.29.1",
    "next": "^12.1.6",
    "nookies": "^2.5.2",
    "numeral": "^2.0.6",
    "raf": "^3.4.1",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-native": "0.68.1",
    "react-native-dotenv": "^2.5.5",
    "react-native-gesture-handler": "^2.4.2",
    "react-native-keyboard-aware-scroll-view": "^0.9.5",
    "react-native-linear-gradient": "^2.5.6",
    "react-native-media-query": "^1.0.9",
    "react-native-paper": "^4.12.1",
    "react-native-progress": "^5.0.0",
    "react-native-read-more-text": "^1.1.2",
    "react-native-reanimated": "^2.8.0",
    "react-native-safe-area-context": "^4.2.5",
    "react-native-screens": "^3.13.1",
    "react-native-share-menu": "^6.0.0",
    "react-native-svg": "^12.3.0",
    "react-native-svg-transformer": "^1.0.0",
    "react-native-vector-icons": "^9.1.0",
    "react-native-view-more-text": "^2.1.0",
    "react-native-web": "^0.17.7",
    "react-native-web-linear-gradient": "^1.1.2",
    "react-redux": "^8.0.1"
  },
  "devDependencies": {
    "@babel/plugin-proposal-class-properties": "^7.14.5",
    "@next/bundle-analyzer": "^12.2.2",
    "@react-native-community/eslint-config": "^2.0.0",
    "@swc/cli": "^0.1.57",
    "@swc/core": "^1.2.179",
    "eslint": "^7.28.0",
    "metro-react-native-babel-preset": "^0.66.0",
    "url-loader": "^4.1.1",
    "webpack": "^5.39.1",
    "webpack-cli": "^4.7.2"
  },
  "jest": {
    "preset": "react-native-web"
  },
  "sideEffects": false
}

注意:只有反应-本地包也使用在网络上必须转移。有些反应-本机包只能在本机中使用,因此将它们转到Web上会增加不必要的大量代码块,这是不好的。本机-本机- Web / Web本机已经比直接为Web制作的普通包更重。

与NextJS保持凉爽的技巧

  • 避免在小型组件上编写条件Platform.OS === 'web',在这些组件中,您计划使用React本机模块或Web模块,这会导致所有组件在web代码上加载不必要的本机包。如果大小不重要,那么您可以忽略它。在末尾添加扩展.web.js.native.js,并分离小代码。例如,我为以下内容编写了单独的函数和组件:Storage.web.jsStorage.native.jsCustomLink.web.jsCustomLink.native.js和hooks useCustomNavigation.web.jsuseCustomNavigation.native.js,因此我调用CustomLink代替NextJS链接/路由器并作出反应--导航CustomLink.web.js使用react-native-media-query包作为高级媒体查询的生命保护程序,用于所有SSR/CSR和本机响应显示。该应用程序可以像普通桌面网站一样在大屏幕上进行重组,然后缩成移动视图,就像NextJS.

上的Material

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/72040787

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档