Nextjs

本篇以nextjs 11作为案例介绍nextjs的接入方式,其它版本nextjs接入方式会在后续补充,如果你在使用时出现问题,请在github上提issue告知我们。

作为主应用

1、安装依赖

npm i @micro-zoe/micro-app --save

2、初始化micro-app

因为webComponent只能运行在浏览器环境,所以我们在pages/_app.jsxuseEffect中进行初始化。

// pages/_app.jsx
import { useEffect } from 'react'
import microApp from '@micro-zoe/micro-app'

function MyApp({ Component, pageProps }) {
  useEffect(() => {
    // 初始化micro-app
    microApp.start()
  }, [])

  return <Component {...pageProps} />
}

export default MyApp

3、在页面中嵌入子应用

因为micro-app只能运行在浏览器环境,所以在useEffect中通过变量控制子应用显示。

// pages/my-page.js
import { useState, useEffect } from 'react'

const MyPage = () => {
  const [show, changeShow] = useState(false)

  useEffect(() => {
    changeShow(true)
  }, [])

  return (
    <div>
      <h1>子应用</h1>
      {
        // name:应用名称, url:应用地址
        show && (<micro-app name='my-app' url='http://localhost:3000/'></micro-app>)
      }
    </div>
  )
}

export default MyPage

Note

  1. name:必传参数,必须以字母开头,且不可以带特殊符号(中划线、下划线除外)
  2. url:必传参数,必须指向子应用的index.html,如:http://localhost:3000/ 或 http://localhost:3000/index.html

作为子应用

1、在主应用中添加ssr配置

当子应用是ssr应用时,主应用需要在micro-app元素上添加ssr属性,此时micro-app会根据ssr模式加载子应用。

<micro-app name='xx' url='xx' ssr></micro-app>

2、设置跨域支持

通过自定义服务设置跨域访问,详情参考 custom-server在新窗口打开

步骤1、在根目录创建server.js

server.js的内容如下:

// server.js
const express = require('express')
const next = require('next')
const config = require('./next.config')

const port = parseInt(process.env.PORT, 10) || 3000
const dev = process.env.NODE_ENV !== 'production'
const app = next({ dev })
const handle = app.getRequestHandler()

app.prepare().then(() => {
  const server = express()

  // 设置跨域支持
  server.all('*', (req, res) => {
    res.setHeader('access-control-allow-origin', '*')
    return handle(req, res)
  })

  server.listen(port, (err) => {
    if (err) throw err
    console.log(`> Ready on http://localhost:${port}/`)
  })
})

步骤2、修改package.json中的scripts,如下:

"scripts": {
  "dev": "node server.js",
  "build": "next build",
  "start": "cross-env NODE_ENV=production node server.js"
}

3、设置assetPrefixpublicRuntimeConfig

next.config.js中设置assetPrefix,为静态资源添加路径前缀,避免子应用的静态资源使用相对地址时加载失败的情况。

// next.config.js
const basePath = '基础路由' // 默认为 '/'
// 静态资源路径前缀
const assetPrefix = process.env.NODE_ENV === 'production' ? `线上域名${basePath}` : `http://localhost:${process.env.PORT || 3000}${basePath}`

module.exports = {
  basePath,
  assetPrefix,
  // 添加 assetPrefix 地址到 publicRuntimeConfig
  publicRuntimeConfig: {
    assetPrefix,
  },
}

assetPrefix只对js、css等静态资源生效,对本地图片无效。

为此我们将assetPrefix作为参数传入publicRuntimeConfig,开发者需要手动通过publicRuntimeConfig补全图片地址。

方式如下:

import getConfig from 'next/config'
const { publicRuntimeConfig } = getConfig()

const Page = () => {
  return (
    <div>
      <img src={`${publicRuntimeConfig.assetPrefix}/local-img.png`} />
    </div>
  )
}

export default Page

4、监听卸载

子应用被卸载时会接受到一个名为unmount的事件,在此可以进行卸载相关操作。

// 监听卸载操作
window.addEventListener('unmount', function () {
  // 执行卸载相关操作
})

Note

nextjs默认支持css module功能,如果你使用了此功能,建议关闭样式隔离以提升性能:<micro-app name='xx' url='xx' disableScopecss></micro-app>

5、切换到iframe沙箱

MicroApp有两种沙箱方案:with沙箱iframe沙箱

默认开启with沙箱,如果with沙箱无法正常运行,可以尝试切换到iframe沙箱。

常见问题

1、使用next/image组件加载图片失败

解决方式:

在部分nextjs版本中(如:nextjs 11),使用next/image组件无法正确引入图片,此时推荐使用img元素代替。

2、无法预加载ssr子应用

原因: 因为ssr应用每个路由地址加载的html、js、css等静态资源都不同,所以无法对ssr子应用使用预加载。

3、控制台报错Cannot read properties of null (reading 'tagName')

原因: 当主应用和子应用都是nextjs应用时,next/head组件冲突。

解决方式: 去掉子应用中next/head组件。

4、webpack.jsonpFunction冲突,导致加载子应用失败

原因: 当主应用和子应用都是官方脚手架创建的项目,容易造成webpack.jsonpFunction冲突。

解决方式: 修改子应用的webpack配置。

jsonpFunction是webpack4中的名称,在webpack5中名称为chunkLoadingGlobal,请根据自己项目的webpack版本设置。

next.config.js中配置webpack:

// next.config.js
module.exports = {
  webpack: (config) => {
    Object.assign(config.output, {
      chunkLoadingGlobal: 'webpackJsonp_自定义名称', // webpack5
      // jsonpFunction: 'webpackJsonp_自定义名称', // webpack4
      globalObject: 'window',
    })
    return config
  },
}

提示

nextjs相关问题可以在nextjs专属讨论贴在新窗口打开下反馈。