基于 vue-cli 2 实现,vue 多模块、vue多项目集成工程

 

业务场景

1.如果项目可能有对应多个不同UI界面;对于这样的场景你可能首先会想到,用样式主题就可以实现,基本的样式或者换肤是可以通过样式实现。但如果要实现更复杂的,比如不同两套UI的界面可能功能显示及样式都有差别,那就不得不单独拆成一个项目,但是这样又会造成每个项目很多冗余代码。

2.如果项目有多个子模块(同时子模块之间又存在互相依赖关系);对于这样的场景是可以把项目独立发布到npm仓库,但是这样又涉及到每个模块都需要独立编译好再发布,实际过程有显得有些繁琐(实际视情况而定)。

对于以上场景可以使用一个项目管理多个子模块也是一个不错的选择。

 

疑问

  1. 多页面:多页面是指一个项目有多个入口,打包是会生成多个html文件,实际开发过程中都是混合在一个项目中开发;
  2. 多模块:是指不同的业务模块可以进行拆分;各自独立运行、也可以互相引用,这一点和通过 npm 发布是类似的;对于一些项目本身不允许发布的情况下,既可以独立开发,又不需要发布到共有仓库(当然也可以通过建立私有仓库解决哈)

 

解决思路

如何划分子模块;

如何分离可复用组件;

如何独立编译,每个子模块独立打包编译、运行;

 

优点

  1. 高复用性
  2. 统一管理依赖库
  3. 不同模块使用的依赖各自按需打包
  4. 模块之间相互独立运行、编译、打包
  5. 模块之间可以直接互相引用,不需要iframe(一般方式是通过iframe嵌入,这样的性能相当差)

 

实现

项目结构

Github项目地址

build:编译、运行相关脚本文件

config:编译、运行相关配置文件

static:不需要编译的静态资源,放到对应的模块目录下

        子模块1

        子模块2

         ...

src:项目源码

        comm:公共模块

                script:公共js文件

                components:公共组件

        子模块1:

                assets:样式、图片等资源文件

                common:业务相关的公共文件

                components:业务组件

                router:路由配置

                store:vuex相关

                views:页面视图

        子模块2:

        子模块3:

                ...

修改配置

1.增加 config/multi.conf.js 多模块配置文件

const path = require('path')
const argvs = process.argv.slice(2)

function resolve(dir) {
  return path.join(__dirname, '..', dir)
}

function getParams(key) {
  let item = argvs.find(item => item.split('=')[0] === key)
  return item ? item.split('=') : []
}

function getModuleAlias() {
  let alias = {}
  importModules.forEach(name => {
    alias[`@${name}`] = resolve(`src/${name}`)
  })
  return alias
}

function getModuleProcess(name) {
  if (!importModules.includes(name)) {
    name = importModules[0]
  }
  return {
    name,
    entry: ["babel-polyfill", `./src/${name}/main.js`],
    alias: resolve(`src/${name}`),
    index: path.resolve(__dirname, `../dist/${name}/index.html`),
    assetsRoot: path.resolve(__dirname, `../dist/${name}/`)
  }
}

// 多项目配置
var importModules = ['project1', 'project2', 'project3']
var lifecycleEvents = String(process.env.npm_lifecycle_event).split(':')
var moduleName = getParams('name')[1] || lifecycleEvents[1]

const multiConfig = {
  modules: importModules,
  moduleAlias: getModuleAlias(),
  process: getModuleProcess(moduleName)
}

module.exports = multiConfig

2.修改 build/webpack.base.conf.js 文件

const multiConfig = require('../config/multi.conf')

// ...省略

module.exports = {
  context: path.resolve(__dirname, '../'),
  entry: multiConfig.process.entry,
  output: {
    path: config.build.assetsRoot,
    filename: '[name].js',
    publicPath: process.env.NODE_ENV === 'production'
      ? config.build.assetsPublicPath
      : config.dev.assetsPublicPath
  },
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@comm': resolve(`src/comm`),
      '@': multiConfig.process.alias,
      ...multiConfig.moduleAlias
    }
  },
  // ...省略
}

3.增加 build/zip.js 文件,用于打包.zip

const pack = require('../package.json')
const path = require('path')
const FileManagerPlugin = require('filemanager-webpack-plugin')
const XEUtils = require('xe-utils')
const multiConfig = require('../config/multi.conf')
const argvs = process.argv.slice(2)

function getParams (key) {
  let item = argvs.find(item => item.split('=')[0] === key)
  return item ? item.split('=') : []
}

let datetime = XEUtils.toDateString(Date.now(), 'yyyyMMddHHmmss')
let plugins = []

let zipPros = getParams('zip')
if (zipPros.length) {
  plugins.push(new FileManagerPlugin({
    onEnd: {
      delete: [
        path.join(__dirname, `../${pack.name}_${multiConfig.process.name}_*.zip`)
      ],
      archive: [{
        source: path.join(__dirname, `../dist/${multiConfig.process.name}`),
        destination: path.join(__dirname, zipPros[1] ? `../${pack.name}_${zipPros[1]}.zip` : `../${pack.name}_${multiConfig.process.name}_${pack.version}_${datetime}.zip`)
      }]
    }
  }))
}

module.exports = plugins

4.修改 config/index.js 文件

{
    // ...省略
  },

  build: {
    // Template for index.html
    index: multiConfig.process.index,

    // Paths
    assetsRoot: multiConfig.process.assetsRoot,
    assetsSubDirectory: 'static',
    assetsPublicPath: '/',
    // ...省略
  }
}

5.修改 package.json 文件,增加独立运行脚本

  "scripts": {
    // ...省略
    "dev:project1": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "dev:project2": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    "dev:project3": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
    // ...省略
  },

6.修改 package.json 文件,增加独立编译脚本

  "scripts": {
    // ...省略
    "build:project1": "node build/build.js name=project1",
    "build:project2": "node build/build.js name=project2",
    "build:project3": "node build/build.js name=project3",
    // ...省略
  },

7.修改 package.json 文件,增加独立打包脚本

  "scripts": {
    // ...省略
    "build:project1:zip": "node build/build.js name=project1 zip",
    "build:project2:zip": "node build/build.js name=project2 zip",
    "build:project3:zip": "node build/build.js name=project3 zip",
    // ...省略
  },

开始使用

1.单个模块启动

npm run dev:project1

npm run dev:project2

npm run dev:project3

2.多模块同时启动

点击右下角的拆分终端按钮,可以同时启动多个模块

3.模块按需、独立编译

npm run build:project1

npm run build:project2

npm run build:project3

 

4.模块按需、独立打包

npm run build:project1:zip

npm run build:project2:zip

npm run build:project3:zip

 

查看项目

 

到此就完了,又愉快的玩耍了哈!

 

Logo

前往低代码交流专区

更多推荐