likes
comments
collection
share

vue-cli实现多模块\页面开发遇到的坑总结~~

作者站长头像
站长
· 阅读数 15

前言

做项目的时候,总是遇到明明是同一种框架技术,组件、方法以及一些js引用都是一样,但是由于业务不同,不能够放在同一个项目,迫不得与新创建一个工程,开启拖拉机模式的把公共的内容重新复制一遍,而且每次改动还需要对多个项目一起改,非常难受。 项目是基于vue-cli5实现的多页面开发与打包,通过 inquirer 实现终端的命令交互实现对目标模块的选中,可以同时启动多个模块的服务,根据不同的modules打包出不同的资源包。闲话少说,直接进入正题

命令行交互 inquirer

修改package.json 的scripts命令,把 serve与build的命令修改,在终端输入的时候执行对应的脚本命令。当npm run serve/build 时,会执行根目录下的/build/cli.js 这个文件

vue-cli实现多模块\页面开发遇到的坑总结~~

cli.js

const chalk = require("chalk");
const { execSync } = require("child_process"); // 开启子分支线程
var inquirer = require("inquirer"); // 命令行交互
var pages = require("../config/pages"); // 多页面的配置信息跟html-webpack-plugin的配置一致, 信息如下
// const pagesConfig = {
//   admin: {
//     entry: "src/modules/user/main.js", // 入口文件
//     template: "static/template/user.html", // 模板文件
//     filename: "admin.html", // 这个文件名很重要,下边会细说
//     title: "admin",
//     outputDir: "dist/admin",
//     chunks: ["chunk-vendors", "chunk-common", "admin"],
//   },
//   client: {
//     entry: "src/modules/client/main.js",
//     filename: "client.html",
//     title: "client",
//     template: "static/template/client.html",
//     outputDir: "dist/client",
//     chunks: ["chunk-vendors", "chunk-common", "client"],
//   },
// };

// module.exports = pagesConfig;

const action = process.argv[2]; // 命令行的第三个参数 npm run serve/build 

const FN_MAP = {
  serve: vueServe,
  build: vueBuild,
};
if (!FN_MAP[action]) {
  return;
}

function getChoicesList() {
  let result = []
  for(let key in pages) {
    result.push({
      value: key, name: key
    })
  }
  return result;
}

// 终端命令行交互会根据用户在终端选择的模块信息返回
inquirer.prompt([
    {
      type: 'checkbox',
      name: "modules",
      default: 0,
      choices: getChoicesList(), // 终端展示的信息合集
    },
  ]).then((result) => {
    // 
    FN_MAP[action](result.modules);
  });

// serve 本地服务,到了这里就跟vue-cli自身启动的服务没有区别了
function vueServe(PAGE_NAME = '') {
  // 开启子线程,启动vue-cli-service serve的服务,通过PAGE_NAME把选中的模块传递到vue.config.js
  execSync(`cross-env PAGE_NAME=${PAGE_NAME} vue-cli-service serve`, {
    stdio: "inherit",
  });
}

// build 打包
function vueBuild(pageName = []) {
  // 遍历,按照次序打包选中的模块 
  pageName.forEach((name) => {
    console.log(`${chalk.blue.bold('Waiting For Server Build...')}`);
    execSync(`cross-env PAGE_NAME=${name} vue-cli-service build`, {
      stdio: "inherit",
    });
  });
}

vue-cli实现多模块\页面开发遇到的坑总结~~

多模块页面 开始接入正题

vue-cli官网提供了配置参考,可以通过vue.config.js内的pages这个配置项实现多个入口的编译 路径如下 cli.vuejs.org/zh/config/#…

vue.config.js

创建vue.config.js,并且配置多页面入口,接入上文,cli.js已经把需要启动的模块通过命令传入到vue.config.js了,那么就在vue.config.js对webpack做一下简单的配置

const { defineConfig } = require('@vue/cli-service')
const ZipPlugin = require('zip-webpack-plugin') // 用来build后的打包压缩
const CopyWebpackPlugin = require('copy-webpack-plugin') // 用于静态资源的copy
const pages = require('./config/pages'); // 页面的参数配置,请往上看,已经有贴出来了
const path = require('path')
const { PAGE_NAME } = process.env; // 在cli.js中的vueServer/vueVuild方法中,传递过来需要处理的模块
function resolve(dir) {
  return path.resolve(__dirname, ".", dir);
}
// 每次启动服务或者打包的时候可能会有多个模块一起,找到inquirer终端选中的模块,添加到pages打包中去
function getPages() {
  let myPages = {}
  let pageList = PAGE_NAME.split(',');
  pageList.forEach(page => {
    let item = {
      [page]: pages[page]
    }
    myPages = {
      ...myPages,
      ...item
    }
  })
  return myPages;

}
const isDev = process.env.NODE_ENV === 'development';
module.exports = defineConfig({
  productionSourceMap: false,
  lintOnSave: false,
  publicPath: isDev ? '/' : './',
  filenameHashing: true,
  outputDir: `dist/${PAGE_NAME}`, // build时,给不同模块打包的资源输出到对应的模块文件夹下
  pages: getPages(), // 多页面配置信息
  configureWebpack: {
    plugins: [
      // 打包完成之后每个模块自动压缩成zip的形式 
      new ZipPlugin({
        path: resolve('dist/zip'),//路径名
	filename: `${PAGE_NAME}.zip`,//打包名
      }),
      // 静态文件copy
      new CopyWebpackPlugin({
        patterns: [
          {
            from: 'static/js',
            to: './static/'
          }
        ]
      })
    ],
  },
  devServer: {
    // 多入口时,根据路径的上下文分发不同的页面入口
    historyApiFallback: {
      rewrites: [
        { from: /^\/admin/, to: '/admin.html' },
        { from: /^\/client/, to: '/client.html' },
      ],
    },
  },

})

看看成果

基本配置已经搞完,那么我们启动一下服务 npm run serve admin服务

vue-cli实现多模块\页面开发遇到的坑总结~~

client服务

vue-cli实现多模块\页面开发遇到的坑总结~~

npm run build

vue-cli实现多模块\页面开发遇到的坑总结~~

想要自己在本地测试以下的也可以安装一个 http-server

    npm install -g http-server 

安装完成之后

    cd dist
    http-servcer

进入到http://127.0.0.1:8080 ,点击对应文件即可预览打包后的文件

仓库链接

gitee.com/list-gitee/…

踩坑点!!!!!!!!!!!!!

上边的配置是已经完成了的,只要对着自己的项目去改一下对应的配置就好了 一开始开发这个功能的时候折磨了我很久,在这里也标记一下最坑的地方 首先,我们先看 入口的配置项 pages.js

const pagesConfig = {
  admin: {
    entry: "src/modules/user/main.js",
    template: "static/template/user.html",
    filename: "admin.html", // 特别关注这个filename
    title: "admin",
    outputDir: "dist/admin",
    chunks: ["chunk-vendors", "chunk-common", "admin"],
  },
  client: {
    entry: "src/modules/client/main.js",
    filename: "client.html", 
    title: "client",
    template: "static/template/client.html",
    outputDir: "dist/client",
    chunks: ["chunk-vendors", "chunk-common", "client"],
  },
};
module.exports = pagesConfig;

在development本地起服务的这个场景下,默认的 http://localhost:8080/ 下面访问的是 index.html,但是,上面我们配置的是filename是 admin.html/client.html 然后恭喜,肯定是访问不到,打开 http://localhost:8080/ 看network可以看到资源是404的,这个就是一个大坑。 那有小伙伴肯定会想(其实是我当初想过的东西~难甭)

Q1: 把filename都改成index.html这样子,不就完事了吗? A1: 改了是没问题,但是变成了每次仅限起一个服务,如果起多个服务的时候,会提示错误

vue-cli实现多模块\页面开发遇到的坑总结~~

冲突中的错误:多个资产向相同的文件名 index.html 发出不同的内容

Q2: 那为什么打包的时候不会出现这个错误? A2:可以看cli.js这个文件,在vueBuild方法的时候,与vueServe不同的地方是用了forEach,由于node是单线程任务,每次build的时候,都是只build一个服务的,并且build出来的 outputDir 是到对应的文件夹下面的。

Q3:那如何去解决? A3:其实上面的代码是已经解决了这个问题,请听我解释。在webpack的官网中,找到了devServer的historyApiFallback这个属性 webpack.docschina.org/configurati… 可以根据链接上的上下文访问到对应的模块, 例如 http://localhost:8080/admin/#/home 访问到 admin 模块 例如 http://localhost:8080/clietn/#/home 访问到 client 模块

到这里,目前遇到的坑点已经全部填完~~~