问题描述
我在使用 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');