【发布时间】:2016-07-04 02:50:56
【问题描述】:
我正在使用 Webpack 构建一个 Angular 1.4 项目。该项目使用了几个 jQuery 插件,这些插件被包装在 angular 指令中。这些指令在内部使用angular.element,可能暗示 angular.element 是真正的 jQuery,而不是 jqLite。
我希望 Angular 自动检测 jQuery 并使用它来代替 jqLite。我尝试在我的入口点模块 app.js:require('jquery') 中本地要求 jquery,并使用 require(expose?$!expose?jQuery!jquery) 全局公开 jQuery。
不过,不管我做什么,angular.element 指的是 jqLite。
我的研究得出了几个发现:
- 即使作为 CommonJS 模块导入时,Angular 也会将自己分配给全局变量
window.angular,因此我不需要使用 Webpack Does Angular assign itself to `window.angular` globally, when loaded as CommonJS module?expose。 - ProviderPlugin 似乎不能解决问题:它不会将 jQuery 暴露给全局命名空间;相反,对于依赖于全局名称 jQuery 的每个模块,它会在其中插入
require('jquery')。我不是 100% 确定,但看起来 Angular 没有直接从全局命名空间访问jQuery,而是尝试在bindJQuery函数中访问window.jQuery,所以这种方法没有帮助:Expose jQuery to real Window object with Webpack . - 出于与 ProviderPlugin 相同的原因,
imports-loader似乎不合适:Angular 想要window.jQuery,而不仅仅是jQuery。 -
使用
expose-loader,jquery 使其成为窗口对象。 我的问题是 Babel 在生成的代码中将其所有导入提升到模块的顶部。因此,虽然require(expose?jquery!jquery)在源文件中位于import angular from "angular"之前,但在bundle 中require("angular")位于文件顶部,在jquery 之前,因此在导入Angular 时,jquery 尚不可用。我想知道,如何使用带有 ECMA6 导入语法的 Webpack 加载器。 - 有人建议在 jquery 中使用
import语法而不是require语法:import "jquery"或import $ from "jquery",而不是require(jquery):(Petr Averyanov:How to use Webpack loaders syntax ( imports/exports/expose) with ECMAScript 6 imports?)。 jquery 源代码是wrapped with a special wrapper,它标识了 jquery 是如何被需要的(使用 AMD/require、CommonJS 或全局使用<script>语句)。基于此,它为 jquery fabric 设置了一个特殊的参数noGlobal,并根据noGlobal的值创建或不创建window.jQuery。从 jquery 2.2.4 开始,不会创建import "jquery"noGlobal === true和window.jQuery。 IIRC,一些旧版本的 jquery 没有将import识别为 CommonJS 导入并将imported jquery 添加到全局命名空间,这允许 angular 使用它。
详情:这是我的app.js:
'use strict';
require("expose?$!expose?jQuery!jquery");
require("metisMenu/dist/metisMenu");
require("expose?_!lodash");
require("expose?angular!angular");
import angular from "angular";
import "angular-animate";
import "angular-messages";
import "angular-resource";
import "angular-sanitize";
import "angular-ui-router";
import "bootstrap/dist/css/bootstrap.css";
import "font-awesome/css/font-awesome.css";
import "angular-bootstrap";
require("../assets/styles/style.scss");
require("../assets/fonts/pe-icon-7-stroke/css/pe-icon-7-stroke.css");
// Import all html files to put them in $templateCache
// If you need to use lazy loading, you will probably need
// to remove these two lines and explicitly require htmls
const templates = require.context(__dirname, true, /\.html$/);
templates.keys().forEach(templates);
import HomeModule from "home/home.module";
import UniverseDirectives from "../components/directives";
angular.module("Universe", [
"ngAnimate",
"ngMessages",
"ngResource",
"ngSanitize",
"ui.router",
"ui.bootstrap",
HomeModule.name,
UniverseDirectives.name,
])
.config(function($urlRouterProvider, $locationProvider, $stateProvider){
// $urlRouterProvider.otherwise('/');
// $locationProvider.html5Mode(true);
$stateProvider
.state('test', {
url: "/test",
template: "This is a test"
});
});
【问题讨论】:
-
如何将 Angular 和 jQuery 加载到应用程序中?它们是捆绑在一起的还是从 CDN 加载的?
-
@HamletHakobyan 它们都在 webpack 包中。
-
你用的是什么角度版本?
-
@maioman Angular 1.4.
-
如果你在 Angular 之前加载 jquery。 angular 足够聪明,可以在 jqlite 上使用 jquery