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

问题描述

我在使用 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>

解决方法

注意:您必须注意不能同时使用 require 和 import 时间在您的节点程序中,更喜欢使用 require 而不是导入,因为您需要使用实验模块 标记功能以运行导入程序。

--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 属性强制定义 jQuery 的 Javascript 文件在页面呈现后加载。由于我在页面中添加了内联 Javascript,它在 before 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');

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...