AngularJS- 使用 LazyLoad- Webpack 动态加载脚本文件

Posted

技术标签:

【中文标题】AngularJS- 使用 LazyLoad- Webpack 动态加载脚本文件【英文标题】:AngularJS- Dynamic Loading of script files using LazyLoad- Webpack 【发布时间】:2017-03-31 07:55:16 【问题描述】:

现在在我的index.html 页面中,我有两个 CDN 文件的链接,一个是 JS,另一个是 CSS 文件。

即 在我的身体底部

https://somedomain.com/files/js/js.min.js

在头脑中

https://somedomain.com/files/css/css.min.css

但是现在我的主页上不需要它们,而只是在一个特定的路线上。因此,我正在研究如何在路由被击中时延迟加载这些 CDN 资源,即/profile,然后才可以?

这些不是通过 bower 或 npm 安装的,而是通过 CDN url 加载的,例如 jquery。如何在 Angular 1 和 Webpack 中基于路由延迟加载?

【问题讨论】:

通过一条特定路线它指的是什么? Angular 有路由,即 /profile。配置文件有一个单独的模块、控制器、视图等我只想在用户导航到该特定路线时加载上述库。 $ocLazyLoad 效果很好 $ocLazyLoad 示例应用freakyjolly.com/how-to-lazy-load-modules-controllers-angularjs 【参考方案1】:

我有这个JStaticLoader repo,方便我在需要时加载静态文件。虽然它没有角化,但您仍然可以在您的应用程序中将其用作directive,直接从您的controller 甚至在$rootScope 中调用它以加载您想要的js

JStaticLoader 使用纯js,不需要依赖。它使用XMLHttpRequest 加载静态文件。

例如在您的app.js 中使用(在$routeChangeStart$stateChangeStart

myApp
.run(['$rootScope', '$http', function ($rootScope, $http) 
    var scriptExists = function (scriptId) 
        if (document.getElementById(scriptId)) 
            return true;
        

        return false;
    ;

    var addLazyScript = function (scriptId, url) 
        if (scriptExists(scriptId)) return;

        var js = document.createElement('script'),
            els = document.getElementsByTagName('script')[0];

        js.id = scriptId;
        js.src = url;
        js.type = "text/javascript";

        els.parentNode.insertBefore(js, els);
    ;

    $rootScope.$on('$routeChangeStart', function (e, current) 
        if (current.controller === 'MainCtrl') 
            var pathUrls = ["https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.8/js/materialize.js"],
                scriptId = 'lazyScript1';

            if (scriptExists(scriptId)) return;

            JStaticLoader(pathUrls,  files: ['js'] , function (vals, totalTime) 
                /* Success */
                for (var i = 0; i < vals.length; i++) 
                    var path = vals[i];
                    addLazyScript(scriptId, path);
                
            , function (error, totalTime) 
                /* Error */
                console.warn(error, totalTime);
            );
        
    );
]);

在上面的示例中,我使用 xhr 获得了一个 js 文件,并在完成后将其作为 script 附加到我的 document 中。然后将从浏览器的缓存中加载脚本。

【讨论】:

XMLHttpRequest 不是外部库。它实际上是内置的,可以得到developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest。通过您自己实现它,您的意思是......在不使用 XMLHttpRequest 的情况下实现 ajax?很抱歉直言不讳,但是……真是个糟糕的主意! @FélixGagnon-Grenier 我不是说 XHR 是外部库.. 但是,JStaticLoader 是.. ... 我一定被这句话误导了:“它使用 XMLHttpRequest 来加载它们。所以,如果你不想为此使用外部库,你可以实现它你” 起初(实际上,很多人后来也读过)并且没有周围的上下文,这完全意味着 XMLHttpRequest 是一个外部库,如果你不想使用它们,你应该实现你自己的.也许只是删除关于 XHR 的那部分,只说 JStaticLoader 是,如果你想避免使用外部库,你应该自己实现它。 考虑一下,这意味着您也可以完全删除它,因为重点是提供答案,而不是告诉操作他们可以自己实现它... :)【参考方案2】:

给你.. 使用 oclazyload 使之成为可能。看看下面的代码。下面链接的一个plunker

我有一个名为 myApp 的模块,如下所示

angular.module('myApp', ['ui.router','oc.lazyLoad'])
    .config(function ($stateProvider, $locationProvider, $ocLazyLoadProvider) 
            $stateProvider
                .state("home", 
                    url: "/home",
                    templateUrl: "Home.html",
                    controller: 'homeCtrl',
                    resolve:  
                        loadMyCtrl: ['$ocLazyLoad', function ($ocLazyLoad) 
                            return $ocLazyLoad.load('homeCtrl.js');
                        ]
                    
                )
            .state("profile", 
                url:"/profile",
                templateUrl: "profile.html",
                 resolve: 
                      loadMyCtrl: ['$ocLazyLoad', function ($ocLazyLoad) 
                      return $ocLazyLoad.load('someModule.js');
                        ]
                    
            )

    );

我有另一个名为 someApp 的模块,如下所示

(function () 
var mynewapp=angular.module('someApp',['myApp']);

mynewapp.config(function()

  //your code to route from here! 

);
      mynewapp.controller("profileCtrl", function ($scope) 

            console.log("reached profile controller");
        );

)();

我有一个 Live Plunker 用于您的演示 here

【讨论】:

【参考方案3】:

严格来说是 Webpack -

Webpack 只是一个模块捆绑器,而不是一个 javascript 加载器。因为它仅从本地存储打包文件,而不从 web 加载文件(除了它自己的块)。尽管可能包含其他模块进入可能执行相同过程的 webpack。

我将只演示一些您可以尝试的模块,因为网上已经定义了很多这样的模块。

因此,从另一个域延迟加载 cdn 的更好方法是使用 javascript 加载器 - script.js

可以通过以下方式加载——

var $script = require("script.js");
 $script = ("https://somedomain.com/files/js/js.min.js or https://somedomain.com/files/css/css.min.css",function()
 //.... is ready now
);

这是可能的,因为 script-loader 只是在全局上下文中评估 javascript。

参考here

关于延迟加载cdn到angular app的问题

以下库Lab JS 是专门为此目的而制作的。 使用这个库加载和阻止 javascript 变得非常简单。

这里有一个例子来演示

<script src="LAB.js"></script>
  <script>
    $LAB
     .script("/local/init.js").wait(function()
       waitfunction();
     );
  <script>

您可以使用require.js

这里是一个加载 jquery 的例子

require.config(
    paths: 
        "jquery": "https://ajax.googleapis.com/ajax/libs/jquery/1.8.1/jquery.min"
    ,
    waitSeconds: 40
  );

您还应该考虑this 文章中的以下段落。

异步加载第三方脚本是获得高性能网页的关键,但这些脚本仍然会阻止 onload。花时间分析您的网络性能数据,并了解这些不那么重要的内容/小部件/广告/跟踪代码是否以及如何影响页面加载时间。

【讨论】:

以上是关于AngularJS- 使用 LazyLoad- Webpack 动态加载脚本文件的主要内容,如果未能解决你的问题,请参考以下文章

ajax+lazyload时lazyload失效问题及解决

图片懒加载之lazyload.js插件使用

Vue-lazyload 的使用

Vue图片懒加载vue-lazyload-使用

Vue图片懒加载vue-lazyload-使用

vue-lazyload 的使用