WP_REGISTER_SCRIPT多个标识符?

时间:2017-10-24 作者:Miloš Đakonović

为了避免多个<script> 标记我定期连接脚本并生成一个bundle.min.js JS文件和\'jsbundle\' 标识符。

问题是,随后添加的东西,如插件,可能依赖于注册的一个或多个库are present, 但包装一般\'jsbundle\'.

有没有办法告诉Wordpress\'jsbundle\' 例如,暗示\'jquery\', \'backbone\', ... 为了1)资源不会被加载两次2)事情不会因为未实现的依赖而失败?

我已经试过了wp_register_script, 建立WP_Scripts() 类,并试图“撒谎”WP关于可用的脚本,但没有运气。

3 个回复
最合适的回答,由SO网友:David Lee 整理而成

要使JavaScript库不加载,因为您已经创建了一个JavaScript库包,请执行以下操作:

A使用以下常规排队方式:

function the_js() {
    wp_enqueue_script(\'bundle_js\', get_template_directory_uri() . \'/js/bundle.js\', array(), false, false);
}

add_action(\'wp_enqueue_scripts\', \'the_js\');
假设您的包中有以下库(列出句柄):

  1. jquery
  2. backbone
  3. colorpicker
  4. bootstrap_js
1、2、3已经在core中,4是第三方,您捆绑了所有4个,因为您不想将4个作为单独的资源加载。

您必须取消注册(如果已注册,则核心库已经注册)并注册其中的每一个,以及捆绑包中的每一个库:

function the_js() {
    wp_enqueue_script(\'bundle_js\', get_template_directory_uri() . \'/js/bundle.js\', array(), false, false);

    //DEREGISTER the SCRIPTS THAT ARE IN YOUR BUNDLE
    wp_deregister_script(\'jquery\'); //because its a Core-Registered Script
    wp_deregister_script(\'backbone\'); //because its a Core-Registered Script
    wp_deregister_script(\'colorpicker\'); //because its a Core-Registered Script

    //REGISTER THEM THIS TIME USING YOUR BUNDLE AS DEPENDENCY
    wp_register_script(\'jquery\', FALSE, array(\'bundle_js\'), \'\', FALSE);//THE KEY HERE IS THE SRC BEING FALSE
    wp_register_script(\'backbone\', FALSE, array(\'bundle_js\'), \'\', FALSE);
    wp_register_script(\'colorpicker\', FALSE, array(\'bundle_js\'), \'\', FALSE);

}

add_action(\'wp_enqueue_scripts\', \'the_js\');
这里的关键是设置$srcFALSE 因此,注册的脚本将是别名,请检查this line 在核心代码中:

// A single item may alias a set of items, by having dependencies, but no source.
if ( ! $obj->src ) {
   return true;
}
目前是什么jquery 在放置jquery 作为依赖项,它不会加载jquery it加载jquery-corejquery-migrate, 这是的注册对象jquery:

object(_WP_Dependency)#329 (6) {
  ["handle"]=>
  string(6) "jquery"
  ["src"]=>
  bool(false)
  ["deps"]=>
  array(2) {
    [0]=>
    string(11) "jquery-core"
    [1]=>
    string(14) "jquery-migrate"
  }
  ["ver"]=>
  string(6) "1.12.4"
  ["args"]=>
  NULL
  ["extra"]=>
  array(0) {
  }
}
所以,bundle_js 当脚本依赖于任何库时,将加载它(jquery, backbone, colorpicker) 它将加载1次,因为WP_Dependencies 检查其是否已在queue 大堆

如果要检查脚本是否已注册,请使用:

global $wp_scripts;
$wp_scripts->query(\'jquery\'); //jquery as example handle
它将返回WP_dependency 对象(如果已注册),false 如果不是。

进一步了解的链接:
class.wp-dependencies.php
class.wp-scripts.php
functions.wp-scripts.php

SO网友:Levi Dulstein

亚历山大提出的解决方案看起来很合理。您可以将所有缩小的依赖项(在我的示例中为libs.js)保存在一个文件中,并将脚本保存在第二个文件中,如下所示:

wp_enqueue_script( \'libs\', get_template_directory_uri() . \'/assets/js/libs.js\', [], \'1.0.0\', true );

// third parameter here will make sure that libs.js is loaded before jsbundle:

wp_enqueue_script( \'jsbundle\', get_template_directory_uri() . \'/assets/js/jsbundle.min.js\', [ \'libs\' ], \'1.0.0\', true );
尽管捆绑脚本是优化页面加载速度的一种众所周知的做法,并且在大多数情况下是一个好主意,但它可能并不总是性能最好的解决方案。我总是会考虑一些其他的选择,并决定什么最适合特定的用例。

CDN

您可能想为您的第三方库使用一个可用的CDN,以获得列出的所有优势in this answer.

E、 g.如果你使用谷歌或Facebook的CDN,你的访问者很有可能已经在浏览器中缓存了流行的脚本,无需再次下载。

在这种情况下,捆绑第三方脚本就失去了这一优势,需要下载整个捆绑包,即使用户已经将部分捆绑包保存在浏览器的缓存中。

您可以使用wp_enqueue_script(), 只需省略$ver 参数,因为您不想刷新缓存的脚本:

wp_enqueue_script( \'jquery\', \'https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js\', [], null, true );
我要考虑的另一件事是注册更多的脚本,并仅在实际使用它们的页面上调用它们。这非常有效,尤其是如果您经常更新脚本。

如果将所有脚本保存在一个捆绑包中,应用一个小更改需要破坏整个脚本的缓存。有时,最好将脚本的各个部分分开,这样就可以只更改实际编辑的块的版本。

假设我使用foo.js 我的主页上没有太多的脚本,所以我不打算很快改变它,但同时我有一个复杂的bar.js 我需要经常维护和刷新的脚本。在这种情况下,最好单独注册脚本。

此外,您的一些库可能只用于不经常访问的子页面(假设我使用masonry 在一个不太受欢迎的子页面上),所以在主页上预装它们可能不是一个好办法。在这种情况下,我会://注册砌体,但不要将其排队wp\\u register\\u脚本(\'砌体\',get\\u template\\u directory\\u uri()。\'/资产/建筑/砌体。min.js’,[],1.0,真);

// foo.js is my implementation of masonry.js
wp_register_script( \'foo.js\', get_template_directory_uri() . \'/assets/js/masonry.min.js\', [ \'masonry\' ], 1.0, true );

// in bar.js I keep functions used all over my page so I enqueue it everywhere immediately
wp_enqueue_script( \'bar.js\', get_template_directory_uri() . \'/assets/js/masonry.min.js\', [], 1.0, true );

// masonry.js and foo.js can wait until the user reaches my less popular subpage as it won\'t be needed most of the time
if ( is_post_type_archive( \'unpopular-posts\' ) ){
    wp_enqueue_script( \'foo.js\' );
}

SO网友:Levi Dulstein

在我之前的回答下与@janh的快速交流激发了我思考不同的方法。我仍然会将所有第三方库缩小为一个单独的捆绑文件(bundlejs), 然后与global合作$wp_scripts 变量(该想法的学分为this thread)

它永远不会完全自动化——正如Janh所注意到的,无法预测其他人会如何在插件或主题中调用脚本。在我的函数中,我使用捆绑文件包含的脚本名称数组。为了加倍打击可能重复的可能性,我还添加了对脚本文件名的支持,而不是仅支持句柄。

请记住,一些管理脚本根本不应该被触碰(请参见codex)

这个解决方案非常原始,我相信它可以在许多方面得到完善,当然可以使用一些重构和WP缓存支持。此外,我也不确定它在现实生活中是如何影响性能的。但这是给你的总体想法,也许还有一些启发:

function switch_dependencies_to_bundle(){
    global $wp_scripts;

    /**
     * array of scripts that our bundle file contains - can be either script name or handle name
     * it\'s never going to be bulletproof tho\', as plugin authors can change file names, i.e.
     * include other version of script
     */
    $bundled = [
        \'jquery\',
        \'masonry\',
        \'masonry-js\',
        \'masonry.js\',
        \'masonry.min.js\', //we can use file name too
        \'backbone\',
        \'backbone.min.js\'
    ];

    $deps_to_remove = [];

    // register our bundle script
    wp_register_script( \'bundlejs\', get_template_directory_uri() . \'/assets/js/bundle.min.js\', [], \'1.0.0\', true );
    wp_enqueue_script( \'bundlejs\' );

    // get registered scripts that our bundle file would duplicate
    foreach( $wp_scripts->registered as $handle => $script ){
        $file_name = substr( $script->src , strrpos( $script->src, "/" ) + 1 );
        if ( in_array( $handle, $bundled, true ) || in_array( $file_name, $bundled, true ) ){
            $deps_to_remove[] = $handle;
        }
    }

    //get rid of redundant scripts with deregister and dequeue.
    //NOTE: does not work for some admin scripts, see codex
    foreach( $deps_to_remove as $script ){
        wp_deregister_script( $script );
        wp_dequeue_script( $script );
    }

    // take care of remaining scripts\' dependencies (they wouldn\'t load with deps missing)
    // add our bundle as dependency, as it contains the same scripts that we just removed
    foreach( $wp_scripts->registered as $script ){
        if ( ! empty( array_intersect( $deps_to_remove, $script->deps ) ) ) {
            $script->deps[] = \'bundlejs\';
            $script->deps = array_diff( $script->deps, $deps_to_remove );
        }
    }
}

// load the function with high priority so it kickes in after other plugins registered their scripts
add_action(\'wp_enqueue_scripts\', \'switch_dependencies_to_bundle\', 9999);

结束