Настроить общий плагин jQuery с помощью Browserify-shim?
Я использую browserify-shim, и я хочу использовать общий плагин jQuery. Я несколько раз просматривал документы Browserify-shim, и я просто не могу понять, что происходит и/или как он знает, где разместить плагины, прикрепить к объекту jQuery и т.д. Вот как выглядит мой файл package.json
"browser": {
"jquery": "./src/js/vendor/jquery.js",
"caret": "./src/js/vendor/jquery.caret.js"
},
"browserify-shim": {
"caret": {
"depends": ["jquery:$"]
}
}
В соответствии с примером, приведенным в документации по обозревателю, я не хочу указывать экспорт, потому что этот плагин (и большинство, если не все плагины jQuery) присоединяется к объекту jQuery. Если я делаю что-то неправильно выше, я не понимаю, почему он не работает (я получаю сообщение об ошибке, когда функция undefined), когда я его использую. См. Ниже:
$('#contenteditable').caret(5); // Uncaught TypeError: undefined is not a function
Итак, мой вопрос в том, как настроить общий jQuery-плагин (который прикрепляется к объекту jQuery) с помощью браузера и браузера-прокладки?
Ответы
Ответ 1
После пересмотра этого и попыток еще чего-то, я, наконец, обернулся вокруг того, что делает прошивка браузера и как его использовать. Для меня был один ключевой принцип, который я должен был понять, прежде чем я, наконец, понял, как использовать прокрутку браузера. Существует два способа использования прокрутки браузера для двух разных вариантов использования: разоблачение и обрезка.
Фон
Предположим, вы хотите просто добавить тэг script в свою разметку (для тестирования или повышения производительности, таких как кеширование, CDN и т.п.). Включив в разметку тег script, браузер попадет в script, запустит его и, скорее всего, добавит свойство в объект окна (также известный как глобальный в JS). Конечно, к этому можно обратиться либо с помощью myGlobal
, либо window.myGlobal
. Но есть проблема с синтаксисом. Это не соответствует спецификации CommonJS, что означает, что если модуль начинает поддерживать синтаксис CommonJS (require()
), вы не сможете его использовать.
Решение
Browserify-shim позволяет указать глобальный, который вы хотите "разоблачить" через синтаксис CommonJS require()
. Помните, что вы могли бы сделать var whatever = global;
или var whatever = window.global;
, но вы не могли бы сделать var whatever = require('global')
и ожидать, что он предоставит вам правильный lib/module. Не путайте имя переменной. Это может быть что угодно. Вы по сути делаете глобальную переменную локальной переменной. Это звучит глупо, но его печальное состояние JS в браузере. Опять же, есть надежда, что, когда lib поддерживает синтаксис CommonJS, он никогда не будет прикрепляться через глобальный объект окна. Это означает, что вы ДОЛЖНЫ использовать синтаксис require()
и назначать его локальной переменной, а затем использовать ее там, где вам это нужно.
Примечание. Я обнаружил, что имя переменной несколько запутано в документах/примерах браузера. Помните, что ключ состоит в том, что вы хотите включить lib , как если бы он был правильно управляемым модулем CommonJS. Итак, что вы в конечном итоге делаете, говорит браузеру, что, когда вам требуется myGlobal require('myGlobal')
, вы просто хотите получить глобальное свойство в объекте window, который равен window.myGlobal
.
На самом деле, если вам интересно, что на самом деле делает функция require, это довольно просто. Вот что происходит под капотом:
var whatever = require('mygGlobal');
становится...
var whatever = window.mygGlobal;
Разоблачение
Итак, с этим фоном, посмотрим, как мы выставляем модуль /lib в нашей конфигурации browser-shim. В принципе, вы указываете браузеру-прокладку две вещи. Имя, с которым вы хотите получить доступ, при вызове require()
и глобальном, которое он должен ожидать, найти на объекте окна. Итак, здесь, где присутствует этот синтаксис global:*
. Посмотрим на пример. Я хочу добавить jQuery в качестве тега script в index.html, чтобы получить лучшую производительность. Вот что мне нужно сделать в моей конфигурации (это было бы в файле package.json или внешнем файле конфигурации JS):
"browserify-shim": {
"jquery": "global:$"
}
Так вот что это значит. Я включил jQuery где-то в другом месте (помните, Browsify-shim не имеет понятия, где мы помещаем наш тег, но это не нужно знать), но все, что мне нужно, - это предоставить свойство $
в объекте window, когда Мне нужен модуль со строковым параметром "jquery". Далее проиллюстрируем. Я также мог бы сделать это:
"browserify-shim": {
"thingy": "global:$"
}
В этом случае мне нужно передать "thingy" в качестве параметра функции require, чтобы вернуть экземпляр объекта jQuery (который он просто получает jQuery из window.$
):
var $ = require('thingy');
И да, опять же, имя переменной может быть любым. Нет ничего особенного в том, что $
совпадает с глобальным свойством $
, используемым в реальной библиотеке jQuery. Хотя имеет смысл использовать одно и то же имя, чтобы избежать путаницы. Это заканчивается ссылкой на свойство $
на объект окна, выбранным значением global:$
в объекте browserify-shim
в package.json.
Шиммирование
Хорошо, так что довольно много обложки. Другая главная особенность браузера-прокладки - подгонка. Так что это? Обрезка делает практически то же самое, что и выставляя, кроме включения lib или модуля в HTML-разметку с чем-то вроде тега script, вы указываете браузеру-прокладку, где можно локально захватить JS файл. Нет необходимости использовать синтаксис global:*
. Поэтому вернемся к нашему примеру jQuery, но на этот раз предположим, что мы не загружаем jQuery из CDN, а просто связываем его со всеми JS файлами. Итак, вот как выглядела бы конфигурация:
"browser": {
"jquery": "./src/js/vendor/jquery.js", // Path to the local JS file relative to package.json or an external shim JS file
},
"browserify-shim": {
"jquery": "$"
},
Эта конфигурация сообщает browserify-shim загружать jQuery из указанного локального пути, а затем захватывать свойство $из объекта window и возвращать его, когда вам требуется jQuery с параметром строки для функции require из jquery. Опять же, для иллюстративных целей вы также можете переименовать это в другое.
"browser": {
"thingy": "./src/js/vendor/jquery.js", // Path to the local JS file relative to package.json or an external shim JS file
},
"browserify-shim": {
"thingy": "$"
},
Что может потребоваться с помощью:
var whatever = require('thingy');
Я бы порекомендовал проверить документы для прокрутки браузера для получения дополнительной информации о длинном синтаксисе, используя свойство exports
, а также свойство depends
, которое позволяет вам указывать прокрутку браузера, если lib зависит от другого Библиотека/модуль. То, что я объяснил здесь, относится к обоим. Надеюсь, это поможет другим, кто пытается понять, что делает прокси-сервер, и как его использовать.
Анонимный обрез
Анонимный shimming - альтернатива Browsify-shim, которая позволяет вам преобразовывать библиотеки, такие как jQuery, в модули UMD, используя опцию browserify --standalone
.
$ browserify ./src/js/vendor/jquery.js -s thingy > ../dist/jquery-UMD.js
Если вы упали в тег script, этот модуль добавит jQuery в объект окна как thingy
. Конечно, это также может быть $
или что угодно.
Если, однако, он require
ed в ваш пакет приложения browserify'd, var $ = require("./dist/jquery-UMD.js");
, у вас будет доступ к jQuery внутри приложения, не добавляя его в объект окна.
Этот метод не требует прокрутки браузера и эксплойтов jQuery CommonJS, где он ищет объект module
и передает флаг noGlobal
в свой factory, который говорит ему не присоединяться к объекту окна.
Ответ 2
Для всех, кто ищет конкретный пример:
Ниже приведен пример файлов package.json
и app.js
для плагина jQuery, который прикрепляется к объекту jQuery
/$
, например: $('div').expose()
. Я не хочу, чтобы jQuery
являлась глобальной переменной (window.jQuery
), когда я ее требую, поэтому для jQuery установлено значение 'exports': null
. Однако, поскольку плагин ожидает глобального объекта jQuery
, к которому он может присоединяться, вы должны указать его в зависимости от имени файла: ./jquery-2.1.3.js:jQuery
. Кроме того, вы должны фактически экспортировать jQuery
global при использовании плагина, даже если вы этого не хотите, потому что плагин не будет работать иначе (по крайней мере, этот конкретный).
package.json
{
"name": "test",
"version": "0.1.0",
"description": "test",
"browserify-shim": {
"./jquery-2.1.3.js": { "exports": null },
"./jquery.expose.js": { "exports": "jQuery", "depends": [ "./jquery-2.1.3.js:jQuery" ] }
},
"browserify": {
"transform": [
"browserify-shim"
]
}
}
app.js
// copy and delete any previously defined jQuery objects
if (window.jQuery) {
window.original_jQuery = window.jQuery;
delete window.jQuery;
if (typeof window.$.fn.jquery === 'string') {
window.original_$ = window.$;
delete window.$;
}
}
// exposes the jQuery global
require('./jquery.expose.js');
// copy it to another variable of my choosing and delete the global one
var my_jQuery = jQuery;
delete window.jQuery;
// re-setting the original jQuery object (if any)
if (window.original_jQuery) { window.jQuery = window.original_jQuery; delete window.original_jQuery; }
if (window.original_$) { window.$ = window.original_$; delete window.original_$; }
my_jQuery(document).ready(function() {
my_jQuery('button').click(function(){
my_jQuery(this).expose();
});
});
В приведенном выше примере я не хотел, чтобы мой код устанавливал любые глобальные переменные, но я временно должен был сделать это, чтобы заставить плагин работать. Если вам нужен только jQuery, вы можете просто сделать это и не нуждаетесь в обходном пути: var my_jQuery = require('./jquery-2.1.3.js')
. Если вам хорошо, когда ваш jQuery отображается как глобальный, вы можете изменить приведенный выше пример package.json
следующим образом:
"browserify-shim": {
"./jquery-2.1.3.js": { "exports": "$" },
"./jquery.expose.js": { "exports": null, "depends": [ "./jquery-2.1.3.js" ] }
Надеюсь, что это поможет некоторым людям, которые искали конкретные примеры (например, я был, когда нашел этот вопрос).
Ответ 3
Просто для полноты, вот метод, который использует jQuery CommonJS, чтобы не беспокоиться о загрязнении объекта window
, не требуя при этом прокладки.
Особенности
- jQuery, включенный в комплект
- плагин включен в комплект
- Отсутствие загрязнения объекта
window
Config
В./package.json добавьте browser
node для создания псевдонимов для местоположений ресурсов. Это чисто для удобства, нет необходимости в том, чтобы ничего подделать, потому что нет связи между модулем и глобальным пространством (script теги).
{
"main": "app.cb.js",
"scripts": {
"build": "browserify ./app.cb.js > ./app.cb.bundle.js"
},
"browser": {
"jquery": "./node_modules/jquery/dist/jquery.js",
"expose": "./js/jquery.expose.js",
"app": "./app.cb.js"
},
"author": "cool.blue",
"license": "MIT",
"dependencies": {
"jquery": "^3.1.0"
},
"devDependencies": {
"browserify": "^13.0.1",
"browserify-shim": "^3.8.12"
}
}
Метод
- Поскольку jQuery является в настоящее время знаком CommonJS, он будет ощущать присутствие объекта
module
, предоставляемого браузером, и возвращает экземпляр, не добавляя его в объект window
.
- В приложении
require
jquery и добавьте его в объект module.exports
(вместе с любым другим контекстом, который должен быть общим).
- Добавьте одну строку в начале плагина, чтобы приложение обращалось к экземпляру jQuery, который он создал.
- В приложении скопируйте экземпляр jQuery в
$
и используйте jQuery с плагином.
- Просмотрите приложение с параметрами по умолчанию и оставьте полученный пакет в тег script в вашем HTML.
Код
app.cb.js
var $ = module.exports.jQuery = require("jquery");
require('expose');
$(document).ready(function() {
$('body').append(
$('<button name="button" >Click me</button>')
.css({"position": "relative",
"top": "100px", "left": "100px"})
.click(function() {
$(this).expose();
})
);
});
в верхней части плагина
var jQuery = require("app").jQuery;
в HTML
<script type="text/javascript" src="app.cb.bundle.js"></script>
Фон
Шаблон, используемый jQuery, должен называть его factory флагом noGlobal
, если он воспринимает среду CommonJS. Он не добавит экземпляр в объект window
и вернет экземпляр, как всегда.
Контекст CommonJS создается браузером по умолчанию. Ниже приведен упрощенный фрагмент из пакета, показывающий структуру модуля jQuery. Для ясности я удалил код, связанный с изоморфной обработкой объекта window
.
3: [function(require, module, exports) {
( function( global, factory ) {
"use strict";
if ( typeof module === "object" && typeof module.exports === "object" ) {
module.exports = factory( global, true );
} else {
factory( global );
}
// Pass this if window is not defined yet
} )( window, function( window, noGlobal ) {
// ...
if ( !noGlobal ) {
window.jQuery = window.$ = jQuery;
}
return jQuery;
}) );
}, {}]
Лучший метод, который я нашел, - это заставить все работать в модульной системе node, а затем будет работать каждый раз после браузера.
Просто используйте jsdom для выравнивания объекта window
, чтобы код был изоморфным. Затем просто сосредоточьтесь на том, чтобы заставить его работать в node. Затем закрепите любой трафик между модулем и глобальным пространством и, наконец, прокрутите его, и он просто будет работать в браузере.
Ответ 4
Я использовал wordpress. Следовательно, я был вынужден использовать ядро wordpress jQuery, доступное в window
объекте.
Он генерировал slick()
не определенную ошибку, когда я пытался использовать плагин slick()
от npm. Добавление browserify-shim
не помогло.
Я немного поработал и выяснил, что require('jquery')
не всегда был последовательным.
В моем javascript файле темы он вызывал ядро wordpress jQuery.
Но в плагине slick
jquery он вызывал последний jquery из модулей node.
Наконец, я смог его решить. Итак, разделите конфигурацию package.json
и gulpfile
.
package.json:
"browserify": {
"transform": [
"browserify-shim"
]
},
"browserify-shim": {
"jquery": "global:jQuery"
},
gulpfile.babel.js:
browserify({entries: 'main.js', extensions: ['js'], debug: true})
.transform(babelify.configure({
presets: ["es2015"]
}))
.transform('browserify-shim', {global: true})
Выполнение преобразования 'browserify-shim' было важной частью, я пропал раньше. Без него browserify-shim
не был согласован.