JQuery 在我的 Twig 模板中的脚本之后加载

JQuery loading after my script inside Twig template

我在使用 jQuery 的 Twig 模板中有一些 Javascript 代码。该脚本似乎在 jQuery 之前加载,因此会引发 $ is not defined 错误。我不明白为什么它在包含 jQuery(用 webpack-encore 编译)的主包之前加载。

JQuery 确实会加载,因为我可以从控制台引用它或将脚本包装在 setTimeout 中以强制稍后加载它。

我有这个基本模板:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>
            {% block title %}Welcome!
            {% endblock %}
        </title>
        {% block stylesheets %}
            {{ encore_entry_link_tags('app') }}
        {% endblock %}

        {% block javascripts %}
            {{ encore_entry_script_tags('app') }}
        {% endblock %}
    </head>
    <body>
        {% block body %}{% endblock %}
    </body>
</html>

页面模板:

{% extends 'base.html.twig' %}
{% block body %}
/// ...
<script>
$.change(/*...*/); // $ is not defined
</script>
{% endblock %}

webpack.config.js:

const path = require('path');
const Encore = require('@symfony/webpack-encore');

if (!Encore.isRuntimeEnvironmentConfigured()) {
    Encore.configureRuntimeEnvironment(process.env.NODE_ENV || 'dev');
}

Encore
    .setOutputPath('public/build/')
    .setPublicPath('/build')
    .enableSassLoader()
    .addEntry('app', './assets/app.js')
    .enableStimulusBridge('./assets/controllers.json')
    .splitEntryChunks()
    .enableSingleRuntimeChunk()
    .cleanupOutputBeforeBuild()
    .enableBuildNotifications()
    .enableSourceMaps(!Encore.isProduction())
    .enableVersioning(Encore.isProduction())
    .configureBabel((config) => {
        config.plugins.push('@babel/plugin-proposal-class-properties');
    })
    .configureBabelPresetEnv((config) => {
        config.useBuiltIns = 'usage';
        config.corejs = 3;
    })

    .autoProvidejQuery()
;
module.exports = Encore.getWebpackConfig();

app.js:

require('./styles/app.scss');
import $ from 'jquery';
global.$ = global.jQuery = $;

这是生成的 HTML:

<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8">
    <link rel="stylesheet" href="/build/app.css">
    <script src="/build/runtime.js" defer></script>
    <script src="/build/app.js" defer></script>
</head>

<body>
    <main class="col p-4 content flex-grow-1">
        <!-- page content -->
        <script>
            // $ is not defined here
        </script>
    </main>
</body>
</html>

NOTE: You must note that you can’t use require and import at the same time in your node program and it is more preferred to use require instead of import as you are required to use the experimental module flag feature to run import program.

--https://www.geeksforgeeks.org/difference-between-node-js-require-and-es6-import-and-export/

上面的文章还提到 require “你可以直接 运行 代码”在这种情况下,代码定义了 $ 函数,所以你想 运行那个。

我的项目如下没有问题:

app.js:

require('./styles/app.scss');
const $ = require('jquery');
window.$ = $;

在 webpack.config.js 中注释以下行:

//.autoProvidejQuery()

在生成的 HTML:

的这些行中发现了问题
<script src="/build/runtime.js" defer></script>
<script src="/build/app.js" defer></script>

defer 属性强制 Javascript 定义了 jQuery 的文件在页面呈现后加载。由于我在页面中添加内联 Javascript,因此它在 之前 app.js.

加载

由于无法在HTML中添加延迟内联Javascript,因此有两种选择:

  • config/packages/webpack_encore.yaml中设置如下配置:
script_attributes:
    defer: false

这将禁用所描述的行为。这个解决方案并不理想,因为在我的情况下使用 defer 是可取的。

  • 在模板外定义 Javascript 代码(使用 encore_entry_script_tags 导入)。

将您的 Javascript 文件保存在 assets/ 中,如果您有与问题中的模板相似的基本模板,请将其导入您的页面模板,如下所示:

{% block javascripts %}
    {{ parent() }}
    {{ encore_entry_script_tags('your_file') }}
{% endblock %}

webpack.config.js中:

Encore
//...
.addEntry('your_file','./assets/your_file.js');