【webpack】动态配置cdn,多模板入口项目搭建

动态配置多模板

  1. 按照这个模板创建项目
    在这里插入图片描述

  2. 安装glob,获取目录下的文件名称

  3. 封装方法utilsConfig,动态生产 page

    // pages 多入口配置
    const path = require("path");
    
    // glob 是 webpack 安装时依赖的一个第三方模块,该模块允许你使用 * 等符号,
    // 例如 lib/*.js 就是获取 lib 文件夹下的所有 js 后缀名的文件
    const glob = require("glob");
    
    // 取得相应的页面路径,因为之前的配置,所以是 src 文件夹下的 pages 文件夹
    const PAGE_PATH = path.resolve(__dirname, "./src/pages");
    
    exports.setPages = (value = "") => {
      let entryFiles = glob.sync(PAGE_PATH.replace(/\\/g, "/") + "/*/*.js");
      let map = {};
      entryFiles.forEach((filePathValue) => {
        const filePath = filePathValue.replace(/\\/g, "/");
        let filename = filePath.substring(
          filePath.lastIndexOf("/") + 1,
          filePath.lastIndexOf(".")
        );
        if (value == "" || value == filename) {
          let tmp =
            filePath.substring(0, filePath.lastIndexOf("/")) + `/${filename}`;
          let conf = {
            // page 的入口
            entry: filePath,
            title: "项目名称_" + filename,
            // 模板来源
            // template: "./public/index.html",
            template: tmp + ".html",
            // 在 dist/index.html 的输出
            filename: (value && value != "" ? "index" : filename) + ".html",
            // 页面模板需要加对应的js脚本,如果不加这行则每个页面都会引入所有的js脚本
            chunks: ["manifest", "vendor", filename],
            id: filename,
            inject: true,
          };
          map[filename] = conf;
        }
      });
      return map;
    };
    
  4. 配置vue.config.js

    const { defineConfig } = require("@vue/cli-service");
    const utils = require("./utilsConfig");
    const path = require("path");
    const pagesList = utils.setPages(appid);
    module.exports = defineConfig({
      // 通过appid进行设置对应的pages,传入''则是设置所有的入口和模板全部
      pages: pagesList,
    });
    
  5. ./router/index.js,配置多项目的功能页面

    import { createRouter, createWebHistory } from "vue-router";
    import store from "@/store";
    // 公共页面
    const routesList = [
      {
        path: "/",
        redirect: "/index",
      },
      {
        path: "index",
        name: "index",
        component: () => import("@/views/index.vue"),
      },
      {
        path: "home",
        name: "home",
        component: () => import("@/views/home.vue"),
      },
    ];
    const router = createRouter({
      history: createWebHistory(process.env.BASE_URL),
      routes: [],
    });
    
    // 重写push
    const originalPush = router.push;
    router.push = function push(valueData) {
      const routerList = router.getRoutes();
      let routeUrl = router.resolve(valueData);
      if (routerList.findIndex((n) => n.path == routeUrl.path) != -1) {
        return originalPush.call(this, valueData).catch((err) => err);
      } else {
        if (
          routeUrl.href.includes("https://") ||
          routeUrl.href.includes("http://")
        ) {
          let hrefUrl = routeUrl.href;
          const index1 = routeUrl.href.indexOf("https://");
          if (index1 != -1) {
            hrefUrl = hrefUrl.substring(index1);
          }
          const index2 = routeUrl.href.indexOf("http://");
          if (index2 != -1) {
            hrefUrl = hrefUrl.substring(index2);
          }
          window.location.href = hrefUrl;
        } else {
          window.location.href = routeUrl.href;
        }
      }
    };
    // 重写replace
    const originalReplace = router.replace;
    router.replace = function replace(valueData) {
      let routeUrl = router.resolve(valueData);
      const routerList = router.getRoutes();
      if (routerList.findIndex((n) => n.path == routeUrl.path) != -1) {
        return originalReplace.call(this, valueData).catch((err) => err);
      } else {
        if (
          routeUrl.href.includes("https://") ||
          routeUrl.href.includes("http://")
        ) {
          let hrefUrl = routeUrl.href;
          const index1 = routeUrl.href.indexOf("https://");
          if (index1 != -1) {
            hrefUrl = hrefUrl.substring(index1);
          }
          const index2 = routeUrl.href.indexOf("http://");
          if (index2 != -1) {
            hrefUrl = hrefUrl.substring(index2);
          }
          window.location.replace(hrefUrl);
        } else {
          window.location.replace(routeUrl.href);
        }
      }
    };
    
    router.beforeEach((to, from, next) => {
      // 判断是否缓存
      console.log(to, from);
      const keepAlive = to.meta.keepAlive;
      const name = to.name;
      if (keepAlive && !store.state.aliveList.includes(name)) {
        store.dispatch("setAliveList", name);
      }
      next();
    });
    
    export default { router, routesList };
    
  6. ./pages/index1/router/index.js./pages/index2/router/index.js,配置对应多项目的对应路由

    // 单个页面
    const routesList = [
      {
        path: "about",
        name: "about",
        component: () => import("../views/about.vue"),
        meta: {
          keepAlive: true,
        },
      },
      {
        path: "index",
        name: "index",
        component: () => import("../views/index.vue"),
      },
    ];
    
    export default routesList;
    
  7. ./pages/index1/index1.js./pages/index2/index2.js,合并路由

    import { createApp } from "vue";
    import store from "@/store";
    const pageInit = require("@/utils/pageInit");
    pageInit.setInit("index1").then((res) => {
      createApp(res.index).use(store).use(res.router).mount("#app");
    });
    
  8. 合并时需要调用封装的方法pageInit

    /* eslint-disable */
    exports.setInit = async (value) => {
      const indexVue = (await import(`@/pages/${value}/${value}.vue`)).default;
      const routerPageList = (await import(`@/pages/${value}/router`)).default;
      const routerObject = (await import(`@/router`)).default;
      routerObject.router.addRoute({
        path: `/${value}`,
        name: `${value}`,
        component: indexVue,
      });
      routerObject.routesList.forEach((item) => {
        routerObject.router.addRoute(`${value}`, {
          ...item,
          meta: { fromList: "common", ...(item.meta || {}) },
        });
      });
      routerPageList.forEach((item) => {
        routerObject.router.addRoute(`${value}`, {
          ...item,
          meta: { fromList: `${value}`, ...(item.meta || {}) },
        });
      });
      return Promise.resolve({ index: indexVue, router: routerObject.router });
    };
    /* eslint-disable */
    

    此时配置成功后,公共页面路由是这样的/index,对应项目的路由是这样的/index1/about/index2/about

last. 具体文档

  • vue多入口、多模板文档

动态配置 cdn

  1. 安装依赖script-ext-html-webpack-plugin

    npm install script-ext-html-webpack-plugin --save--dev
    
  2. vue.config.js配置

    const { defineConfig } = require("@vue/cli-service");
    const utils = require("./utilsConfig");
    const path = require("path");
    const pagesList = utils.setPages(appid);
    // externals
    const externals = {
      vue: "Vue",
      "vue-router": "VueRouter",
      vuex: "Vuex",
      axios: "axios",
    };
    
    // CDN外链,会插入到对应的.html中
    const cdn = {
      css: [],
      js: [
        "https://unpkg.com/vue@3.2.13/dist/vue.global.js",
        "https://unpkg.com/vue-router@4.0.3/dist/vue-router.global.js",
        "https://unpkg.com/axios/dist/axios.min.js",
        "https://unpkg.com/vuex@4.0.0/dist/vuex.global.js",
      ],
    };
    module.exports = defineConfig({
      configureWebpack: (config) => {
        config.name = "xxx";
        config.externals = externals;
      },
      chainWebpack: (config) => {
        config.plugins.delete("preload"); // TODO: need test
        config.plugins.delete("prefetch"); // TODO: need test
    
        // 别名 alias
        config.resolve.alias
          .set("@", resolve("src"))
          .set("assets", resolve("src/assets"))
          .set("api", resolve("src/api"))
          .set("views", resolve("src/views"))
          .set("components", resolve("src/components"));
    
        // 多入口的
        Object.keys(pagesList).forEach((key) => {
          config.plugin("html-" + key).tap((args) => {
            if (args.length > 0) {
              args[0].title = "项目名称" + key;
              args[0].cdn = cdn;
            }
            return args;
          });
        });
        // 单一的
        // config
        //   .plugin("html-index")
        //   .tap((args) => {
        //     args[0].title = "项目名称";
        //     args[0].cdn = cdn;
        //     return args;
        //   })
      },
    });
    
    • 我们可以通过vue inspect,查看当前项目 webpack 配置,进而知道注入 cdn 模块的名称

      在这里插入图片描述

  3. 模板对应的html

    <!DOCTYPE html>
    <html lang="">
      <head>
        <meta charset="utf-8" />
        <meta http-equiv="X-UA-Compatible" content="IE=edge" />
        <meta name="viewport" content="width=device-width,initial-scale=1.0" />
        <link rel="icon" href="<%= BASE_URL %>favicon.ico" />
        <title><%= htmlWebpackPlugin.options.title %></title>
        <% for (var i in
        htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css) { %>
        <link
          href="<%= htmlWebpackPlugin.options.cdn.css[i] %>"
          rel="preload"
          as="style"
        />
        <% } %>
      </head>
    
      <body>
        <noscript>
          <strong
            >We're sorry but <%= htmlWebpackPlugin.options.title %> doesn't work
            properly without JavaScript enabled. Please enable it to
            continue.</strong
          >
        </noscript>
        <div id="app"></div>
        <% for (var i in
        htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js) { %>
        <script src="<%= htmlWebpackPlugin.options.cdn.js[i] %>"></script>
        <% } %>
        <!-- built files will be auto injected -->
      </body>
    </html>
    
    • 主要是对 htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.css htmlWebpackPlugin.options.cdn&&htmlWebpackPlugin.options.cdn.js进行循环

通过命令打包不同的文件

  1. 修改 package.json,添加命令

    "scripts": {
       "serve-index1": "vue-cli-service serve --Key=index1 --port 8081",
       "serve-index2": "vue-cli-service serve --Key=index2 --port 8082",
       "build-index1": "vue-cli-service build --Key=index1 ",
       "build-index2": "vue-cli-service build --Key=index2",
        ...
      },
    
  2. 修改vue.config.js

    const { defineConfig } = require("@vue/cli-service");
    // 获取命令的参数
    const argvData = process.argv;
    // 获取appid
    let appid = "";
    argvData.forEach((item) => {
      if (item.includes("--Key=")) {
        appid = item.split("=")[1];
      }
    });
    // 获取outputDir的路径
    const getOutputDir = (value) => {
      if (value == "") {
        return "dist/";
      } else {
        return `dist/${value}`;
      }
    };
    
    module.exports = defineConfig({
      outputDir: getOutputDir(appid),
    });
    
  3. 运行 npm run build-index1npm run build-index2

    在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/66200.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

RaabitMQ(三) - RabbitMQ队列类型、死信消息与死信队列、懒队列、集群模式、MQ常见消息问题

RabbitMQ队列类型 Classic经典队列 这是RabbitMQ最为经典的队列类型。在单机环境中&#xff0c;拥有比较高的消息可靠性。 经典队列可以选择是否持久化(Durability)以及是否自动删除(Auto delete)两个属性。 Durability有两个选项&#xff0c;Durable和Transient。 Durable表…

图像 检测 - DETR: End-to-End Object Detection with Transformers (arXiv 2020)

图像 检测 - DETR: End-to-End Object Detection with Transformers - 端到端目标检测的Transformers&#xff08;arXiv 2020&#xff09; 摘要1. 引言2. 相关工作2.1 集预测2.2 Transformers和并行解码2.3 目标检测 3. DETR模型References 声明&#xff1a;此翻译仅为个人学习…

【VisualGLM】大模型之 VisualGLM 部署

目录 1. VisualGLM 效果展示 2. VisualGLM 介绍 3. VisualGLM 部署 1. VisualGLM 效果展示 VisualGLM 问答 原始图片 2. VisualGLM 介绍 VisualGLM 主要做的是通过图像生成文字&#xff0c;而 Stable Diffusion 是通过文字生成图像。 一种方法是将图像当作一种特殊的语言进…

SAS-数据集SQL水平合并

一、SQL水平合并基本语法 sql的合并有两步&#xff0c;step1&#xff1a;进行笛卡尔乘积运算&#xff0c;第一个表的每一行合并第二个表的每一行&#xff0c;即表a有3行&#xff0c;表b有3行&#xff0c;则合并后3*39行。笛卡尔过程包含源数据的所有列&#xff0c;相同列名会合…

mysql进阶篇(二)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★ React从入门到精通★ ★前端炫酷代码分享 ★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff…

3.2用互斥元保护共享数据

概述 于是&#xff0c;你有一个类似于上一节中链表那样的共享数据结构&#xff0c;你想要保护它免于竞争条件以及可能因此产生的不变量损坏。如果你可以将所有访问该数据结构的代码块标记为互斥的&#xff08;mutually exclusive)&#xff0c;岂不是很好&#xff1f;如果任何线…

DuDuTalk:AI语音工牌在家装行业门店销售场景有何应用价值?

随着科技的不断发展&#xff0c;人工智能技术的应用也越来越广泛。作为人工智能技术的一种应用形式&#xff0c;AI语音工牌在家装行业门店销售场景中起到了重要的作用。本文将从AI语音工牌的定义、功能、应用场景以及优势等方面&#xff0c;探讨它在家装行业门店销售场景的应用…

Qt多线程编程

本章介绍Qt多线程编程。 1.方法 Qt多线程编程通常有2种方法&#xff1a; 1)通过继承QThread类&#xff0c;实现run()方法。 2)采用QObject::moveToThread()方法。 方法2是Qt官方推荐的方法&#xff0c;本文介绍第2种。 2.步骤 1)创建Worker类 这里的Worker类就是我们需要…

【Docker】Windows下docker环境搭建及解决使用非官方终端时的连接问题

目录 背景 Windows Docker 安装 安装docker toolbox cmder 解决cmder 连接失败问题 资料获取方法 背景 时常有容器方面的需求&#xff0c;经常构建调试导致测试环境有些混乱&#xff0c;所以想在本地构建一套环境&#xff0c;镜像调试稳定后再放到测试环境中。 Windows …

音视频--视频数据传输

参考文献 H264码流RTP封装方式详解&#xff1a;https://blog.csdn.net/water1209/article/details/126019272H264视频传输、编解码----RTP协议对H264数据帧拆包、打包、解包过程&#xff1a; https://blog.csdn.net/wujian946110509/article/details/79129338H264之NALU解析&a…

汽车维修保养记录查询API:实现车辆健康状况一手掌握

在当今的数字化世界中&#xff0c;汽车维修保养记录的查询和管理变得前所未有地简单和便捷。通过API&#xff0c;我们可以轻松地获取车辆的维修和保养记录&#xff0c;从而实现对手中车辆健康状况的实时掌握。 API&#xff08;应用程序接口&#xff09;是进行数据交换和通信的标…

RocketMQ第二课-核心编程模型以及生产环境最佳实践

一、回顾RocketMQ的消息模型 ​ 上一章节我们从试验整理出了RocketMQ的消息模型&#xff0c;这也是我们使用RocketMQ时最直接的指导。 二、深入理解RocketMQ的消息模型 1、RocketMQ客户端基本流程 <dependency><groupId>org.apache.rocketmq</groupId>&…

以http_proxy和ajp_proxy方式整合apache和tomcat(动静分离)

注意&#xff1a;http_proxy和ajp_proxy的稳定性不如mod_jk 一.http_proxy方式 1.下载mod_proxy_html.x86_64 2.在apache下创建http_proxy.conf文件&#xff08;或者直接写到conf/httpd.conf文件最后&#xff09; 3.查看server.xml文件 到tomcat的安装目录下的conf/serve…

【word密码】word设置只读,如何取消?

Word文件打开之后发现是只读模式&#xff0c;那么我们如何取消word文档的只读模式呢&#xff1f;今天给大家介绍几种只读模式的取消方法。 属性只读 有些文件可能是在文件属性中添加了只读属性&#xff0c;这种情况&#xff0c;我们只需要点击文件&#xff0c;再次查看文件属…

命令模式(C++)

定义 将一个请求(行为)封装为一个对象&#xff0c;从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。 应用场景 在软件构建过程中&#xff0c;“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合——比…

后端进阶之路——深入理解Spring Security配置(二)

前言 「作者主页」&#xff1a;雪碧有白泡泡 「个人网站」&#xff1a;雪碧的个人网站 「推荐专栏」&#xff1a; ★java一站式服务 ★ ★前端炫酷代码分享 ★ ★ uniapp-从构建到提升★ ★ 从0到英雄&#xff0c;vue成神之路★ ★ 解决算法&#xff0c;一个专栏就够了★ ★ 架…

CAD绘制法兰、添加光源、材质并渲染

首先绘制两个圆柱体&#xff0c;相互嵌套 在顶部继续绘制圆柱体&#xff0c;这是之后要挖掉的部分 在中央位置绘制正方形 用圆角工具&#xff1a; 将矩形的四个角分别处理&#xff0c;效果&#xff1a; 用拉伸工具 向上拉伸到和之前绘制的圆柱体高度齐平 绘制一个圆柱体&#…

golang 自定义exporter - 端口连接数 portConnCount_exporter

需求&#xff1a; 1、计算当前6379 、3306 服务的连接数 2、可prometheus 语法查询 下面代码可直接使用&#xff1a; 注&#xff1a; 1、windows 与linux的区分 第38行代码 localAddr : fields[1] //windows为fields[1] &#xff0c; linux为fields[3] 2、如需求 增加/修改/删除…

opencv基础48-绘制图像轮廓并切割示例-cv2.drawContours()

绘制图像轮廓&#xff1a;drawContours函数 在 OpenCV 中&#xff0c;可以使用函数 cv2.drawContours()绘制图像轮廓。该函数的语法格式是&#xff1a; imagecv2.drawContours( image, contours, contourIdx, color[, thickness[, lineType[, hierarchy[, maxLevel[, offset]]…

【数据结构与算法】Vue3实现选择排序动画效果与原理拆解

系列文章目录 删除有序数组中的重复项 JavaScript实现选择排序 文章目录 系列文章目录1、选择排序的原理1.1、选择排序的基本步骤1.2、拆解思路 2、动画演示原理3、代码实现4、优化后的选择排序5、用Vue3实现选择排序的动画效果&#xff08;第二部分的动画效果图&#xff09; …