微前端 —— menu&&project1(React)

前言

        微前端 —— 理論篇
        微前端 —— portal項目
        上一篇中,咱們完成了portal項目的搭建,算是完成了整個微前端架構的一半工程了。如今開始新建咱們的業務小應用。css

Menu項目

        menu項目是做爲頁面的菜單顯示的,主要用於路由的控制。
        項目的結構以下:
圖片描述
        接下來就開始實現它吧。前端

  1. 新建項目文件夾menu,在根目錄執行npm init -y
  2. 安裝相關依賴,因爲react相關的幾個依賴已經在portal項目中抽離出來,所以咱們這不須要安裝了。

         package.js文件內容以下:node

{
      "name": "menu",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "start": "webpack-dev-server --config ./webpack.dev.js --port 8235",
        "build": "webpack --config ./webpack.config.js -p"
      },
      "keywords": [],
      "author": "",
      "license": "ISC",
      "dependencies": {
        "antd": "^3.20.7",
        "babel-plugin-import": "^1.12.0",
        "copy-webpack-plugin": "^5.0.4",
        "react-router": "4.3.1",
        "react-router-dom": "4.3.1",
        "single-spa-react": "2.8.1",
        "@reach/router": "1.2.1"
      },
      "devDependencies": {
        "@babel/core": "7.0.0",
        "@babel/plugin-proposal-class-properties": "7.0.0",
        "@babel/plugin-proposal-decorators": "7.1.0",
        "@babel/plugin-proposal-object-rest-spread": "7.0.0",
        "@babel/plugin-syntax-dynamic-import": "^7.0.0",
        "@babel/preset-env": "7.0.0",
        "@babel/preset-react": "7.0.0",
        "autoprefixer": "9.1.5",
        "babel-core": "6.26.3",
        "babel-loader": "8.0.0",
        "clean-webpack-plugin": "0.1.19",
        "css-loader": "1.0.0",
        "postcss-loader": "3.0.0",
        "style-loader": "0.23.0",
        "webpack": "4.17.1",
        "webpack-cli": "3.1.0",
        "webpack-dev-server": "^3.1.14"
      }
    }

        新建src文件夾,在src文件夾下建立components文件夾,在components文件夾中新建文件Menu.js,內容以下:react

import React from 'react'
    import {Menu, Icon} from 'antd'
    import { Link } from '@reach/router'
    const MenuItem = Menu.Item
    
    export default class Menu_ extends React.Component {
        render () {
            return (
                <div style={menuStyle}>
                    <h1>menu!</h1>
                    <Menu>
                        <MenuItem key="1">
                            <Icon type="pie-chart"/>
                            <Link to='/' style={{display: 'inline'}}>主頁</Link>
                        </MenuItem>
                        <MenuItem key="2">
                            <Icon type="desktop"/>
                            <Link to='/page1' style={{display: 'inline'}}>頁面1</Link>
                        </MenuItem>
                        <MenuItem key="32">
                            <Icon type="desktop"/>
                            <Link to='/page2' style={{display: 'inline'}}>頁面2</Link>
                        </MenuItem>
                        <MenuItem key="4">
                            <Icon type="desktop"/>
                            <Link to='/page3' style={{display: 'inline'}}>頁面3</Link>
                        </MenuItem>
                        <MenuItem key="5">
                            <Icon type="desktop"/>
                            <Link to='/page4' style={{display: 'inline'}}>頁面4</Link>
                        </MenuItem>
                    </Menu>
                </div>
            )
        }
    }
    
    const menuStyle = {
        display: 'inline-block',
        position: 'fixed',
        width: '300px',
        height: '100%'
    }

        如今咱們已經實現了菜單的頁面代碼。在src目錄下新建文件root.component.js,引入導出Menu組件webpack

import React from 'react'
    import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom'
    import Menu from './components/Menu'
    
    export default class Root extends React.Component {
    
      state = {
        hasError: false
      }
    
      componentDidCatch (error, info) {
        this.setState({hasError: true})
      }
    
      render () {
        return (
          <Menu />
        )
      }
    }

        在src目錄下新建文件set-public-path.jsgit

// For lazy loading within an application to work you need to set webpack's public path
    // basically webpack's internal module system always looks for code-splits (modules) at the root
    export default function setPublicPath() {
      return Promise.all([getUrl()]).then(values => {
        const [url] = values
        const webpackPublicPath = url.slice(0, url.lastIndexOf('/') + 1)
    
        __webpack_public_path__ = webpackPublicPath
        return true
      })
    }
    
    function getUrl () {
      return window.System.resolve('@portal/menu')
    }

        在src目錄下新建文件menu.js,用於組件的註冊github

import React from 'react'
    import ReactDOM from 'react-dom'
    import singleSpaReact from 'single-spa-react'
    import { property } from 'lodash'
    import setPublicPath from './set-public-path.js'
    
    const reactLifecycles = singleSpaReact({
      React,
      ReactDOM,
      loadRootComponent: () => import(/* webpackChunkName: "people-app" */'./root.component.js').then(property('default')),
      domElementGetter,
    })
    
    export const bootstrap = [
      () => {
        return setPublicPath()
      },
      reactLifecycles.bootstrap,
    ]
    
    export const mount = [
      reactLifecycles.mount,
    ]
    
    export const unmount = [
      reactLifecycles.unmount,
    ]
    
    export const unload = [
      reactLifecycles.unload,
    ]
    
    function domElementGetter() {
      let el = document.getElementById("menu");
      if (!el) {
        el = document.createElement('div');
        el.id = 'menu';
        document.body.appendChild(el);
      }
    
      return el;
    }

        最後編寫webpack配置文件,在項目根目錄下建立文件webpack.config.jswebpack.dev.js


        webpack.config.jsweb

/* eslint-env node */
    const webpack = require('webpack')
    const path = require('path');
    const CleanWebpackPlugin = require('clean-webpack-plugin');
    const CopyWebpackPlugin = require('copy-webpack-plugin');
    
    module.exports = {
      entry: path.resolve(__dirname, 'src/menu.js'),
      output: {
        filename: 'menu.js',
        library: 'menu',
        libraryTarget: 'amd',
        path: path.resolve(__dirname, 'build/menu'),
      },
      mode: 'production',
      module: {
        rules: [
          {parser: {System: false}},
          {
            test: /\.js?$/,
            exclude: [path.resolve(__dirname, 'node_modules')],
            loader: 'babel-loader',
          },
          {
            test: /\.css$/,
            exclude: [path.resolve(__dirname, 'node_modules')],
            use: [
              'style-loader',
              {
                loader: 'css-loader',
                options: {
                  modules: true,
                  localIdentName: '[path][name]__[local]',
                },
              },
              {
                loader: 'postcss-loader',
                options: {
                  plugins() {
                    return [
                      require('autoprefixer')
                    ];
                  },
                },
              },
            ],
          },
          {
            test: /\.css$/,
            include: [path.resolve(__dirname, 'node_modules')],
            exclude: [/\.krem.css$/],
            use: ['style-loader', 'css-loader'],
          },
        ],
      },
      resolve: {
        modules: [
          __dirname,
          'node_modules',
        ],
      },
      plugins: [
        new CleanWebpackPlugin(['build/menu']),
        new CopyWebpackPlugin([
          {from: path.resolve(__dirname, 'src/Menu.js')}
        ]),
      ],
      devtool: 'source-map',
      externals: [
        /^@portal\/*/,
        /^lodash$/,
        /^single-spa$/,
        /^rxjs\/?.*$/,
        /^react$/,
        /^react\/lib.*/,
        /^react-dom$/,
        /.*react-dom.*/,
      ],
    };

        公共依賴就別單獨打包了
        webpack.dev.jsnpm

/* eslint-env node */
    const config = require('./webpack.config.js');
    const webpack = require('webpack');
    
    config.plugins.push(new webpack.NamedModulesPlugin());
    config.plugins.push(new webpack.HotModuleReplacementPlugin());
    config.devServer = {
      headers: {
        "Access-Control-Allow-Origin": "*",
      },
    }
    
    config.mode = 'development'
    
    module.exports = config;

        menu項目的源碼大概就這些 bootstrap

3.project1
        project1項目也是經過react框架實現的,主要是實現了不一樣路由匹配不一樣頁面,最後運行打包的時候,暴露出一個js文件,共portal項目調用。詳細的就不闡述了,跟menu項目大同小異,也就只是頁面代碼不同。



        menu源碼地址
        project1源碼地址
        項目源碼地址

        微前端 —— 理論篇
        微前端 —— portal項目
        微前端 —— project2項目(VUE)

相關文章
相關標籤/搜索