N年前写的微前端笔记——demo-感受Single-Spa(二)

5. 感受Single-Spa

我们先通过小demo,来感受下Single-Spa如何实现一个项目两个框架同时存在的

开始

  1. 创建根目录

mkdir single-spa-app
cd single-spa-app

  1. 初始化项目

npm init -y

  1. 安装依赖,直接展示package.json上的依赖吧
  • dependencies 用 “npm i 依赖名” 来安装
  • devDependencies 用 “npm i 依赖名 -D” 来安装
"dependencies": {
  "react": "^16.13.1",
  "react-dom": "^16.13.1",
  "single-spa": "^5.4.0",
  "single-spa-react": "^2.14.0",
  "single-spa-vue": "^1.8.2",
  "vue": "^2.6.11"
},
"devDependencies": {
  "@babel/core": "^7.9.6",
  "@babel/plugin-proposal-object-rest-spread": "^7.9.6",
  "@babel/plugin-syntax-dynamic-import": "^7.8.3",
  "@babel/preset-env": "^7.9.6",
  "@babel/preset-react": "^7.9.4",
  "babel-loader": "^8.1.0",
  "clean-webpack-plugin": "^3.0.0",
  "css-loader": "^3.5.3",
  "html-loader": "^1.1.0",
  "style-loader": "^1.2.1",
  "vue-loader": "15.9.1",
  "vue-template-compiler": "^2.6.11",
  "webpack": "^4.43.0",
  "webpack-cli": "^3.3.11",
  "webpack-dev-server": "^3.10.3"
}
  1. 创建html入口文件
  • 在根目录创建

touch index.html

<html>
  <body>
    <div id="react"></div>
    <div id="vue"></div>
    <script src="/dist/single-spa.config.js"></script>
  </body>
</html>
  1. 创建业务代码文件夹及内容
  • 由于我们需要同时存在vue和react两个框架,所以我们可以创建两个框架的业务入口

mkdir src src/vue src/react

  • 在src/vue下创建vue.app.js和main.vue
// vue.app.js

import Vue from 'vue';
import singleSpaVue from 'single-spa-vue';
import Hello from './main.vue'

const vueLifecycles = singleSpaVue({
  Vue,
  appOptions: {
    el: '#vue',
    render: r => r(Hello)
  } 
});

export const bootstrap = [
  vueLifecycles.bootstrap,
];

export const mount = [
  vueLifecycles.mount,
];

export const unmount = [
  vueLifecycles.unmount,
];
<!-- main.vue -->
<template>
  <div>
      <h1>Hello from Vue</h1>
  </div>
</template>

  • 在src/react下创建main.app.js和root.component.js
// main.app.js
import React from 'react';
import ReactDOM from 'react-dom';
import singleSpaReact from 'single-spa-react';
import Home from './root.component.js';

// if (process.env.NODE_ENV === 'development') {
//   // 开发环境直接渲染
//   ReactDOM.render(<Home />, document.getElementById('react'))
// }

function domElementGetter() {
  return document.getElementById("react")
}

// 创建生命周期实例
const reactLifecycles = singleSpaReact({
  React,
  ReactDOM,
  rootComponent: Home,
  domElementGetter,
})

// 项目启动钩子
export const bootstrap = [
  reactLifecycles.bootstrap,
];

// 项目挂载钩子
export const mount = [
  reactLifecycles.mount,
];

// 项目卸载钩子
export const unmount = [
  reactLifecycles.unmount,
];
// root.component.js 

import React from "react"

const App = () => <h1>Hello from React</h1>

export default App
  1. webpack.config.js
const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = {
  mode: 'development',
  entry: {
    'single-spa.config': './single-spa.config.js',
  },
  output: {
    publicPath: '/dist/',
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist'),
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
        exclude: /node_modules/,
      }, {
        test: /\.js$/,
        exclude: [path.resolve(__dirname, 'node_modules')],
        loader: 'babel-loader',
        exclude: /node_modules/,
      },
      {
        test: /\.vue$/,
        loader: 'vue-loader',
        exclude: /node_modules/,
      }
    ],
  },
  node: {
    fs: 'empty'
  },
  resolve: {
    alias: {
      vue: 'vue/dist/vue.js'
    },
    modules: [path.resolve(__dirname, 'node_modules')],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new VueLoaderPlugin()
  ],
  devtool: 'source-map',
  externals: [],
  devServer: {
    historyApiFallback: true
  }
};

7.配置babel

  • 配置babel有好几种方式,我们采用.babelrc的方式

touch .babelrc

{
  "presets": [
    ["@babel/preset-env", {
      "targets": {
        "browsers": ["last 2 versions"]
      }
    }],
    ["@babel/preset-react"]
  ],
  "plugins": [
    "@babel/plugin-syntax-dynamic-import",
    "@babel/plugin-proposal-object-rest-spread"
  ]
}
  1. 重点: 创建single-spa的配置
  • 首先创建single-spa.config.js

touch single-spa.config.js

  • 这个文件是你注册所有应用程序的地方,这些应用程序将是主单页应用程序的一部分,每次调用registerApplication都会注册一个新应用程序,并接受三个参数:
    • App name 应用名称
    • Loading function 加载应用的入口文件
    • Activity function 判断是否加载应用程序的逻辑,函数返回true则加载,返回false则不加载
import { registerApplication, start } from 'single-spa'

registerApplication(
  'vue', 
  () => import('./src/vue/vue.app.js'), // 加载vue项目的入口文件
  (location) => location.pathname === "/react" ? false : true // 当url为/vue的时候,返回true, 返回true代表渲染
);



registerApplication(
  'react',
  () => import('./src/react/main.app.js'),
  (location) => location.pathname === "/vue"  ? false : true
);

// 所以,如果url为/的时候,那第一个和第二个registerApplication函数的第三个参数,都是返回true,这样就说明当部位/react或/vue时,就都渲染

start();
  1. 创建启动脚本
  • 在package.json中修改scripts如下:
"scripts": {
  "start": "webpack-dev-server --open",
  "build": "webpack --config webpack.config.js -p"
}
  1. 这时候你可以运行程序了

npm start

访问

# 地址为非/react或非/vue时,vue和react都加载
http://localhost:8080/

# 地址为/react时,只加载react应用
http://localhost:8080/react

# 地址为/vue时,只加载vue应用
http://localhost:8080/vue

重点

  • 在本demo中,最关键的其实就以下几点:
  1. webpack.config.js的入口改为single-spa.configs.js
  2. single-spa.config.js文件主要用于注册应用程序
  3. src/vue/vue.app.js和src/react/main.app.js业务入口文件需要创建微服务生命周期实例并导出,以便外部跟踪该应用的声明活动。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值