多项目集成下的工程脚手架配置方案

发表于 2年以前  | 总阅读数:303 次

一、背景

随着项目的复杂和功能的增加,一个工程下可能存在多个项目,这个时候我们单独开项目去开发的话项目代码会冗余,项目后期的维护成本也很高,而代码的冗余会造成静态资源包加载时间变长、执行时间也会变长,进而很直接的影响性能和体验。为了解决此问题我们需要实现多项目的分模块打包,且项目之间共享组件和依赖,运行、打包时互不干扰。

二、应用场景

以一个后台管理系统为例,我们同时有运营管理系统、商家管理系统、设备管理系统,还有一些内部的管理系统,这几个系统的菜单管理、权限管理、用户管理等相同业务模块较多,业务组件以及UI组件都要遵循公司的规范,这种情况下就可以用一个repo来管理这些系统, 所有的设计文档、源代码、文件都放在一个repo里面。

三、技术方案

本文基于vue-cli3,核心是vue.config.js文件。vue-cli2实现方法类似,核心是webpack.config.js文件,这里不做过多阐述。

1. 功能

  • 项目区分命令化
  • 项目配置化
  • 路由模块管理
  • 项目生成脚本化

2. 技术点

  • process.argv[1] :获取命令行参数
  • cross-env[2]:设置环境
  • fs-extra[3]:命令行生成项目
  • chalk[4]:命令行美化
  • inquirer[5]:命令行交互
  • node-progress[6]:加载进度条

3. 思路

我们知道在package.json中有项目启动、打包的命令,我们可以从这里入手。我们的思路大概是这样的:

  1. 通过命令行输入的项目名称打包指定项目 处理命令行参数;
  2. 配置公共文件和项目配置文件;
  3. 设置当前运行/打包项目(project.js);
  4. 打包项目所需的模块和资源;
npm run dev projectA           # 运行开发环境下的projectA项目
npm run build:dev projectA     # 打包开发环境下的projectA项目
npm run build projectA         # 打包projectA项目

4. 目录结构

.
├── README.md
├── babel.config.js
├── config                 # 配置项
│   ├── build.js           # 打包配置文件
│   ├── copy.js            # 项目生成文件
│   ├── dev.js             # 开发配置文件
│   ├── project.js         # 获取项目项目信息
│   └── projectConfig.js   # 项目配置文件(和普通的脚手架配置项一样) 
├── package.json           # 项目依赖
├── postcss.config.js      # postcss配置文件
├── project                # 工程信息配置             
│   ├── index.js
│   ├── module             # 公共路由模块
│   └── projects           # 公共项目信息
├── public
│   └── index.html
├── src
│   ├── assets              # 公共资源文件
│   │   └── logo.png
│   ├── components          # 公共组件
│   │   ├── 404.vue
│   │   └── main.vue
│   └── projects            # 项目目录(独立的路由 状态管理 接口请求)
│       ├── projectA
│       ├── projectB
│       └── projectC
├── temp                    # 项目模板文件(可根据项目需求定制)
│   ├── App.vue
│   ├── components
│   ├── main.js
│   ├── page
│   │   └── Home.vue
│   ├── router.js
│   └── store.js
├── vue.config.js           # 核心配置文件
└── yarn.lock

13 directories, 26 files

好了,我们的视图目录结构大概就是上面的样子,我们期望的是打包src目录下这个A项目就像打包一个完整的项目一样。那么如何实现这部分呢?

5. 流程图

6 项目配置

1) 修改package.json配置

这里就不得不提到cross-env这个模块,我们之前在生产、沙箱、测试、开发环境时也会用到这个命令。

npm i --save-dev cross-env

代码:

"scripts": {
  "serve": "vue-cli-service serve",
  "build": "vue-cli-service build",
  "lint": "vue-cli-service lint",
  "dev": "cross-env NODE_ENV=development node config/dev.js",
  "test": "cross-env NODE_ENV=test node config/dev.js",
  "pre": "cross-env NODE_ENV=preview node config/dev.js",
  "prd": "cross-env NODE_ENV=production node config/dev.js",
  "build:dev": "cross-env NODE_ENV=development node config/build.js",
  "build:test": "cross-env NODE_ENV=test node config/build.js",
  "build:pre": "cross-env NODE_ENV=preview node config/build.js",
  "build:prd": "cross-env NODE_ENV=production node config/build.js",
  "copy": "node config/copy.js"
}

2) 编写项目代码

此版本为简易demo,配置完运行命令和打包命令我们就可以编写项目中的业务代码了。

路径:src/projects/projectA/App.vue


<template>
  <div id="app">
    <img
      alt="项目A"
      src="https://dummyimage.com/300x300/FF0097/fff&text=PROJECT-A"
    />
    <router-view />
  </div>
</template>

<style lang="scss">
......
</style>

路径:src/projects/projectB/App.vue

<template>
  <div id="app">
    <img
      alt="项目B"
      src="https://dummyimage.com/300x300/ff55ee/fff&text=PROJECT-B"
    />
    <router-view />
  </div>
</template>

<style lang="scss">
......
</style>

3) 配置项目信息

在项目根目录建立config文件夹,在其中新建projectsConfig.js写入:

const projectName = require("./project");
const config = {
  // $ 项目A
  projectA: {
    pages: {
      index: {
        entry: "src/projects/projectA/main.js",
        template: "public/index.html",
        filename: "index.html",
        title: "projectA"
      },
    },
    devServer: {
      port: 7777, // 端口地址
     }
  },
  // $ 项目B
  projectB: {
    pages: {
      index: {
        entry: "src/projects/projectB/main.js",
        template: "public/index.html",
        filename: "index.html",
        title: "projectB"
      },
    },
    devServer: {
      port: 8888, // 端口地址
     }
  },
  // $ 项目C
  projectC: {
    pages: {
      index: {
        entry: "src/projects/projectC/main.js",
        template: "public/index.html",
        filename: "index.html",
        title: "projectC"
      },
    },
    devServer: {
      port: 9999, // 端口地址
     }
  },
};

const configObj = config[projectName.name];
// $ 这里导出的是当前运行项目的配置
module.exports = configObj;

4) 运行时配置

开始前先讲下process.argv它返回的是一个数组,其中包含启动 Node.js 进程时传入的命令行参数。第一个元素将是process.execPath, 第二个元素将是正在执行的 JavaScript文件的路径,其余元素将是任何其他命令行参数。

const fse = require("fs-extra");
const chalk = require('chalk');
let projectName = process.argv[2]; // $ 获取命令行项目名称
if(!projectName) throw(chalk`{red.bold.bgWhite ------项目不存在,请检查配置------}`);
console.log(chalk.red.bold(`正在运行---${projectName}项目`), `${process.env.NODE_ENV} 环境`, )
fse.writeFileSync('./config/project.js', `exports.name = '${projectName}'`)

let exec = require('child_process').execSync;
exec('npm run serve', {stdio: 'inherit'});

Tips:命令行参数是固定格式npm run dev projectA,少了项目名称会提示项目不存在。

5) 打包时配置

这里就比较简单了,根据当前项目名称进行打包即可

const projectName = process.argv[2]
const fse = require("fs-extra");

fse.writeFileSync('./config/project.js', `exports.name = '${projectName}'`)
const str = 'npm run build'
const exec = require('child_process').execSync;
exec(str, {stdio: 'inherit'});

6) 配置Vue CLI

  • 通过process.argv获取当前命令行的项目名称,判断命令行的项目名称是否在项目列表里,如果没有给出异常提示;
  • 设置当前运行项目的脚手架信息;
  • 终端命令提示;
const path = require('path')
const conf = require('./config/projectConfig'); // $ 当前项目
const chalk = require('chalk'); // $ 终端颜色设置插件
const ProgressBarPlugin = require('progress-bar-webpack-plugin'); // $ 进度条插件

const PROJECTNAME = require('./config/project.js').name;
if(!conf) throw(chalk`{black.bold.bgWhite ------项目不存在,请检查配置 777------}`);
const assetsDir = ''

function getAssetPath (assetsDir, filePath) {
  return assetsDir
    ? path.posix.join(assetsDir, filePath)
    : filePath
}

module.exports = {
  pages: conf.pages, // $ 当前项目页面
  outputDir: "dist/" + projectName + "/", // $ 设置输出目录名
  assetsDir: 'static',  // $ 增加static文件夹
  lintOnSave: process.env.NODE_ENV !== 'production', // $ 是否在开发环境下通过 eslint-loader 在每次保存时 lint 代码
  productionSourceMap: false, // $ 是否需要生产环境的 source map
  devServer: conf.devServer, // $ 看项目需求 可配可不配
  configureWebpack: {
    plugins: [
      new ProgressBarPlugin({  
        width: 50,                     // 默认20,进度格子数量即每个代表进度数,如果是20,那么一格就是5。
        // format: 'build [:bar] :percent (:elapsed seconds)',
        format: chalk.blue.bold("build") + chalk.yellow('[:bar] ') + chalk.green.bold(':percent') + ' (:elapsed秒)',
        // stream: process.stderr,        // 默认stderr,输出流
        // complete: "~",                 // 默认“=”,完成字符
        clear: false,                  // 默认true,完成时清除栏的选项
        // renderThrottle: "",            // 默认16,更新之间的最短时间(以毫秒为单位)
        callback() {                   // 进度条完成时调用的可选函数
          console.log(chalk.red.bold("---->>>>编译完成<<<<----"))
        }
    }),
    ]
  },
  // $ 对内部的 webpack 配置进行更细粒度的修改
  chainWebpack: config => {
    // $ 修复HMR
    config.resolve.symlinks(true);
    // $ 制定环境打包js路径
    const filename = getAssetPath(
      assetsDir,
      `static/js/[name].js`
    )
    config.mode('production').devtool(false).output.filename(filename).chunkFilename(filename)
    config.performance.set('hints', false)
  },
  css: {
    extract: false // $ 是否将组件中的 CSS 提取至一个独立的 CSS 文件中 (而不是动态注入到 JavaScript 中的 inline 代码)
    loaderOptions: {
      sass: {
        implementation: require('sass'),
        fiber: require('fibers')
      }
    }
  }
}

配置终端插件的效果图:

7) 运行效果

写到这里我们就建立一个完整的小vue项目了,我们运行看看效果:

npm run dev projectA

如图:

8) 打包效果

npm run build:projectA

cd dist/projectA

live-server --port=9999

live-server是一个具有实时加载功能的小型服务器,在项目中用live-server作为一个实时服务器查看开发的网页或项目效果

7. 自动化生成模板项目

1) 流程图

2) 思路整理

  • 本文涉及到脚手架里边与命令行交互的知识点,感兴趣的可以拷贝文末demo去练习下;
  • 这里主要是针对新建的模板做拷贝处理,流程节点中执行拷贝命令后输入的项目名称提示在本地已存在是否需要删除或者覆盖,根据实际业务场景做处理,这里不做过多探讨;
  • 示例代码涉及到的模板代码存放在工程根目录,也可以放在src目录下,不做强制要求;

3) 执行命令

npm run copy

4) 示例代码

  • fs-extra:添加了未包含在原生fs模块中的文件系统方法,并向fs方法添加了promise支持;
  • fse.pathExists:判断当前要拷贝的项目是否存在;
  • fse.copy:拷贝模板文件到指定目录;
const fse = require("fs-extra");
const chalk = require("chalk");
const path = require("path");
const inquirer = require("inquirer");
inquirer
  .prompt([
    {
      type: "input",
      name: "projectName",
      message: "请输入要生成的项目名称",
    },
  ])
  .then((answers) => {
    createProject(answers.projectName);
  });

// $ 拷贝项目模板
const createProject = (projectName) => {
  const currentTemp = path.join(`./src/projects/${projectName}`);
  // $ 判断当前要拷贝的项目是否存在
  fse.pathExists(currentTemp, (err, exists) => {
    console.log(err, exists); // $ => null, false
    // $ 根据用户选择是否替换本项目或者删除本项目
    if (exists) {
      // $ 这里也可以覆盖原项目或者dong
      inquirer
        .prompt([
          {
            type: "input",
            name: "projectName",
            message: "项目已存在,请重新输入项目名称",
          },
        ])
        .then((answers) => {
          createProject(answers.projectName);
        });
      //   throw chalk`{red.bold.bgWhite >>> ${projectName} <<< 项目已经存在}`;
    } else {
      // $ 拷贝模板文件到指定目录
      fse.copy("./temp", path.join(`./src/projects/${projectName}`), (err) => {
        // if (err) return console.error(err)
        if (err)
          throw chalk`{red.bold.bgWhite ------${projectName}项目拷贝失败 ${err}------}`;
        console.log(chalk.red.bold(`--->>>${projectName}项目拷贝成功`));
      });
    }
  });
};

8 优缺点

优点:

  • 方便统一管理项目;
  • 项目之间共享组件和依赖;
  • 运行、打包时互不干扰;
  • 支持同时运行多个项目;
  • 对于公共模块一次提交可以解决所有子项目的问题;

缺点:

  • 执行拷贝模板命令后生成的项目需要在config/projectConfig.js文件中手动配置项目信息;
  • 随着项目的增加路由文件的提交在每次代码的时候都需要进行Code Review,不然的话不熟悉项目的同学很可能会在解决冲突的过程中把冲突的模块删除;
  • 随着程序规模的不断增加,代码量的增加,文档的增加,整个repo会变得越来越大;

四、思考

有兴趣的童鞋可以考虑以下两个问题:

  1. 项目中有公共路由我们应该如何处理?
  2. 状态管理和接口管理在这个工程下如何处理?

五、总结

通过以上的分析,我们应该对同一工程下多项目配置化打包的大概流程有基本的了解,而上边的方案也只是其中的一种实现方式。写本文的目的主要是给大家提供一种思路,以后在遇到工程需要定制化的时候就可以通过更改脚手架的配置来实现。

Demo:[https://github.com/licairen/multi_project_demo](

参考资料

[1]process.argv: http://nodejs.cn/api/process/process_argv.html

[2]cross-env: https://www.jianshu.com/p/ecf1a4130add

[3]fs-extra: https://github.com/jprichardson/node-fs-extra

[4]chalk: https://github.com/chalk/chalk

[5]inquirer: https://github.com/SBoudrias/Inquirer.js

[6]node-progress: https://github.com/tj/node-progress#options

本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/QKOsTD_UXIN8lD2y8jxR9A

 相关推荐

刘强东夫妇:“移民美国”传言被驳斥

京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。

发布于:1年以前  |  808次阅读  |  详细内容 »

博主曝三大运营商,将集体采购百万台华为Mate60系列

日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。

发布于:1年以前  |  770次阅读  |  详细内容 »

ASML CEO警告:出口管制不是可行做法,不要“逼迫中国大陆创新”

据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。

发布于:1年以前  |  756次阅读  |  详细内容 »

抖音中长视频App青桃更名抖音精选,字节再发力对抗B站

今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。

发布于:1年以前  |  648次阅读  |  详细内容 »

威马CDO:中国每百户家庭仅17户有车

日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。

发布于:1年以前  |  589次阅读  |  详细内容 »

研究发现维生素 C 等抗氧化剂会刺激癌症生长和转移

近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。

发布于:1年以前  |  449次阅读  |  详细内容 »

苹果据称正引入3D打印技术,用以生产智能手表的钢质底盘

据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。

发布于:1年以前  |  446次阅读  |  详细内容 »

千万级抖音网红秀才账号被封禁

9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...

发布于:1年以前  |  445次阅读  |  详细内容 »

亚马逊股东起诉公司和贝索斯,称其在购买卫星发射服务时忽视了 SpaceX

9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。

发布于:1年以前  |  444次阅读  |  详细内容 »

苹果上线AppsbyApple网站,以推广自家应用程序

据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。

发布于:1年以前  |  442次阅读  |  详细内容 »

特斯拉美国降价引发投资者不满:“这是短期麻醉剂”

特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。

发布于:1年以前  |  441次阅读  |  详细内容 »

光刻机巨头阿斯麦:拿到许可,继续对华出口

据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。

发布于:1年以前  |  437次阅读  |  详细内容 »

马斯克与库克首次隔空合作:为苹果提供卫星服务

近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。

发布于:1年以前  |  430次阅读  |  详细内容 »

𝕏(推特)调整隐私政策,可拿用户发布的信息训练 AI 模型

据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。

发布于:1年以前  |  428次阅读  |  详细内容 »

荣耀CEO谈华为手机回归:替老同事们高兴,对行业也是好事

9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI操控无人机能力超越人类冠军

《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。

发布于:1年以前  |  423次阅读  |  详细内容 »

AI生成的蘑菇科普书存在可致命错误

近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。

发布于:1年以前  |  420次阅读  |  详细内容 »

社交媒体平台𝕏计划收集用户生物识别数据与工作教育经历

社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”

发布于:1年以前  |  411次阅读  |  详细内容 »

国产扫地机器人热销欧洲,国产割草机器人抢占欧洲草坪

2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。

发布于:1年以前  |  406次阅读  |  详细内容 »

罗永浩吐槽iPhone15和14不会有区别,除了序列号变了

罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。

发布于:1年以前  |  398次阅读  |  详细内容 »
 相关文章
Android插件化方案 5年以前  |  237227次阅读
vscode超好用的代码书签插件Bookmarks 2年以前  |  8063次阅读
 目录