首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >基于webpack应用的动态vue路由器

基于webpack应用的动态vue路由器
EN

Stack Overflow用户
提问于 2020-12-21 12:13:05
回答 1查看 447关注 0票数 1

日安。

问题定义:

我想在动态路径上部署我的Vue应用程序,该应用程序利用vue-路由器,动态路径应该由WebServer控制,在历史模式下使用vue-路由器,并避免为每个部署重新打包应用程序。

F.e.

http://localhost/subpath/index.htmlhttp://localhost/another-subpath/index.html运行相同的应用程序

由于vue路由器配置是在打包阶段(f.e. )完成的。由webpack),因此设计不被控制后的包装阶段,使这一简单但如此常见的设置不可行。

此外,vue-具有相当复杂的生命周期,不允许在应用程序级别轻松重写基本设置。

此外,webpack最终将实际资源硬编码到html主体中,这确保了客户端在加载时正确地使用它们,但是由于块是相互依赖的--它们几乎不可能被动态注入/编辑。应用程序完整性失败的情况下,那些修改后-多莫雷事件.

研究:我的搜索到目前为止还没有找到任何可行的选项来设置这样的配置。

EN

回答 1

Stack Overflow用户

发布于 2020-12-21 12:13:05

我想出了几个可行的解决方案。

问题之一是,要动态更改应用程序的根,并使其在动态URL上正常运行,更改路由器基础并不是唯一需要的东西。

在vue+webpack的情况下,将实际脚本添加到构建阶段的index.html中,从而--因此--最终会被硬编码。

我想出了几乎没有办法解决这个问题。

丑陋的解决方案:

Regex-在index.html上,在web服务器级别替换资源URL,并为您的vue路由器基础设置硬编码。

这是很有问题的做法,但是可行的。

不幸的是,我没有那种方法的示例,所以-我不能提供任何示例,但是这应该非常简单:

在servlet端,伪代码:

代码语言:javascript
运行
复制
let fileContent = getFileContent(requested_file_name);
if (servingFile == "index.html") {
  fileContent = fileContent.regexReplace("http://url_hardcoded_at_packaging_stage", "http://url_application_is_deployed_at");
  fileContent = fileContent.regexReplace("setting_token_in_your_index_html", "http://url_application_is_deployed_at");
}
return fileContent;

此外,您还需要在您的setting_token_in_your_index_html中添加此index.html

代码语言:javascript
运行
复制
<head>
<script type="text/javascript">
window.my_app_settings = {routerBase:"setting_token_in_your_index_html"}
</script>
</head>

并在vue-路由器级别使用它:

代码语言:javascript
运行
复制
export default new Router({
  mode: "history",
  base: window.my_app_settings.routerBase,
  routes: [...]
  ...
});

从某种意义上说,这种方法是好的,没有必要在vue-app级别上修改任何东西,而且所有的更改只能保存在servlet端,不管它是什么。

此外,它对vue-app本身也有0的性能影响。

仍然很难看,但至少从代码的角度看要好得多:

vue-app base-aware。

这个解决方案并不简单,但在所有主要的Web服务器上都能可靠地工作,可以概括为基于Web提供的cookie在应用程序init上动态添加vue-资源。

这种方法允许“优雅地”修改所有资源URL,对性能方面的影响最小,并尽可能保持动态。

这种方法包括对打包和应用程序级别的一些小更改,并且还依赖于cookie向应用程序提供有关自定义基础的信息。

提供来自服务器的自定义URL:

在您的web服务器上添加cookie报头(所有主要的web服务器都支持这样的功能):

(f.e.在斯卡巴特拉)

代码语言:javascript
运行
复制
val contextShiftCookie = "subpath_where_ui_deployed";
val cookie = new Cookie("ui_deployment_root", contextShiftCookie );
cookie.setPath("/");
response.addCookie( cookie );

(**index.html**): 应用程序修改

<head>部分:

代码语言:javascript
运行
复制
    <script type="text/javascript">
      // Build script names, for later injection.
      let stringsJs = [
      <% for (let js in htmlWebpackPlugin.files.js) { %>
        "<%= htmlWebpackPlugin.files.js[js] %>",
      <% } %>
      ];
      let stringsCss = [
      <% for (let css in htmlWebpackPlugin.files.css) { %>
        "<%= htmlWebpackPlugin.files.css[css] %>",
      <% } %>
      ];
      // Simple vanilla Cookie getter (replace with something else if needed).
      function getCookie(cname) {
        var name = cname + "=";
        var decodedCookie = decodeURIComponent(document.cookie);
        var ca = decodedCookie.split(';');
        for(var i = 0; i < ca.length; i++) {
          var c = ca[i];
          while (c.charAt(0) == ' ') {
            c = c.substring(1);
          }
          if (c.indexOf(name) == 0) {
            return c.substring(name.length, c.length);
          }
        }
        return "";
      }
      // Simple vanilla onDomReady handler (replace with something else if needed).
      (function(exports, d) {
        function domReady(fn, context) {
          function onReady(event) {
            d.removeEventListener("DOMContentLoaded", onReady);
            fn.call(context || exports, event);
          }
          function onReadyIe(event) {
            if (d.readyState === "complete") {
              d.detachEvent("onreadystatechange", onReadyIe);
              fn.call(context || exports, event);
            }
          }
            d.addEventListener && d.addEventListener("DOMContentLoaded", onReady) ||
            d.attachEvent      && d.attachEvent("onreadystatechange", onReadyIe);
          }
          exports.domReady = domReady;
      })(window, document);

      // Calculating vue router base.
      let routerBase = "/";
      if (getCookie("ui_deployment_root")) {
        routerBase = getCookie("ui_deployment_root");
        // console.log("Found base cookie", routerBase);
      } else {
        console.log("No base cookie found");
      }
      let scriptsBase = routerBase == "/"? "" : routerBase;

      // Prefilling basic settings.
      window.my_vue_app_config = {
        routerBase: routerBase
      };

      function loadOneScript(){
          if (window.my_vue_app_scripts.length > 0) {
            let currentScript = window.my_vue_app_scripts.shift();
            currentScript.onload = loadOneScript;
            document.getElementsByTagName("body").item(0).append(currentScript);
          }
        }

      // Injecting scripts using deployment context.
      domReady(function(event) {
        let head = document.getElementsByTagName("head").item(0);
        stringsCss.forEach(css => {
          let script = document.createElement("link");
          script.setAttribute("rel","stylesheet");
          script.setAttribute("href", scriptsBase + css);
          head.append(script);
        });
        window.my_vue_app_scripts = [];
        stringsJs.forEach(js => {
          let script = document.createElement("script");
          script.setAttribute("type","text/javascript");
          script.setAttribute("src", scriptsBase + js);
          window.my_vue_app_scripts.push(script);
        });
        loadOneScript();
      });
    </script>

一步一步解释:

在加载nicely.

  • Gather实际块之前,
  1. 可以使用base设置,以确保vue-router可以使用WebPack中的所有脚本名(请参见let stringsJslet stringsCss)
  2. Load all css中的DomReady (因为css是在运行中使用的,所以加载它们没有任何具体的内容)。它们应该是可用的)。请参阅stringsCss.forEach
  3. 逐个加载所有js块,因为这是确保webpack编辑的应用程序被正确初始化的唯一方法(参见stringsJs.forEachloadOneScript
  4. 加载的方式是,每个脚本(块)一旦被客户端(浏览器)加载和使用,就请求另一个块)。这确保了应用程序的完整性,以及正确的初始化,无论它是如何处理packed.
  5. Chunks的,都是按照webpack提供的正确顺序处理的--以确保完整性。

vue-路由器更改:

在路由器级别使用新设置:

代码语言:javascript
运行
复制
export default new Router({
  mode: "history",
  base: window.my_vue_app_config.routerBase,
  routes: [...]
  ...
});

Webpack机制变化:

为了支持webpack的定制捆绑:

代码语言:javascript
运行
复制
<% for (let js in htmlWebpackPlugin.files.js) { %>
  "<%= htmlWebpackPlugin.files.js[js] %>",
<% } %>

,您需要修改/app/build/webpack.ENV.conf.js文件:

代码语言:javascript
运行
复制
...
new HtmlWebpackPlugin({
    ...
    inject: false,
    ...
}),

.ENV.应该是您想要的包目标,但我建议对所有环境进行更改,因为这样您就可以确保您的index.html更改在所有环境中都能正常工作。

性能考虑事项:

这是我对这种“顺序脚本注入”最关心的问题,因为从性能的角度来看,这听起来很糟糕。

但是,让我最惊讶的是,根据所有主要Web客户端(浏览器)的测试,与应用程序的完全静态服务相比,实际测试只显示了JavaScript processing time中的~ major。

这基本上使性能问题在我的案例中变得无关紧要,但我们担心这在您的情况下可能会有所不同。

对应用程序生命周期的其他影响是完全可以忽略的,至少在我的情况下是这样的(对App的总体影响小于0.05ms )。

附注:

由于这种方法是我自己发展出来的--我希望有建设性的批评和改进建议:)

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/65392586

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档