Commit e48f54b5 authored by Jacob Schatz's avatar Jacob Schatz

Merge branch 'enable-webpack-code-splitting' into 'master'

Enable webpack code splitting

Closes #32989

See merge request !12032
parents 30c7fef0 598baa55
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
"gon": false, "gon": false,
"localStorage": false "localStorage": false
}, },
"parser": "babel-eslint",
"plugins": [ "plugins": [
"filenames", "filenames",
"import", "import",
......
...@@ -2,7 +2,6 @@ ...@@ -2,7 +2,6 @@
/* global Flash */ /* global Flash */
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import * as Emoji from './emoji';
const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd'; const animationEndEventString = 'animationend webkitAnimationEnd MSAnimationEnd oAnimationEnd';
const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd'; const transitionEndEventString = 'transitionend webkitTransitionEnd oTransitionEnd MSTransitionEnd';
...@@ -24,27 +23,9 @@ const categoryLabelMap = { ...@@ -24,27 +23,9 @@ const categoryLabelMap = {
flags: 'Flags', flags: 'Flags',
}; };
function renderCategory(name, emojiList, opts = {}) { class AwardsHandler {
return ` constructor(emoji) {
<h5 class="emoji-menu-title"> this.emoji = emoji;
${name}
</h5>
<ul class="clearfix emoji-menu-list ${opts.menuListClass || ''}">
${emojiList.map(emojiName => `
<li class="emoji-menu-list-item">
<button class="emoji-menu-btn text-center js-emoji-btn" type="button">
${Emoji.glEmojiTag(emojiName, {
sprite: true,
})}
</button>
</li>
`).join('\n')}
</ul>
`;
}
export default class AwardsHandler {
constructor() {
this.eventListeners = []; this.eventListeners = [];
// If the user shows intent let's pre-build the menu // If the user shows intent let's pre-build the menu
this.registerEventListener('one', $(document), 'mouseenter focus', '.js-add-award', 'mouseenter focus', () => { this.registerEventListener('one', $(document), 'mouseenter focus', '.js-add-award', 'mouseenter focus', () => {
...@@ -78,10 +59,10 @@ export default class AwardsHandler { ...@@ -78,10 +59,10 @@ export default class AwardsHandler {
const $target = $(e.currentTarget); const $target = $(e.currentTarget);
const $glEmojiElement = $target.find('gl-emoji'); const $glEmojiElement = $target.find('gl-emoji');
const $spriteIconElement = $target.find('.icon'); const $spriteIconElement = $target.find('.icon');
const emoji = ($glEmojiElement.length ? $glEmojiElement : $spriteIconElement).data('name'); const emojiName = ($glEmojiElement.length ? $glEmojiElement : $spriteIconElement).data('name');
$target.closest('.js-awards-block').addClass('current'); $target.closest('.js-awards-block').addClass('current');
this.addAward(this.getVotesBlock(), this.getAwardUrl(), emoji); this.addAward(this.getVotesBlock(), this.getAwardUrl(), emojiName);
}); });
} }
...@@ -139,16 +120,16 @@ export default class AwardsHandler { ...@@ -139,16 +120,16 @@ export default class AwardsHandler {
this.isCreatingEmojiMenu = true; this.isCreatingEmojiMenu = true;
// Render the first category // Render the first category
const categoryMap = Emoji.getEmojiCategoryMap(); const categoryMap = this.emoji.getEmojiCategoryMap();
const categoryNameKey = Object.keys(categoryMap)[0]; const categoryNameKey = Object.keys(categoryMap)[0];
const emojisInCategory = categoryMap[categoryNameKey]; const emojisInCategory = categoryMap[categoryNameKey];
const firstCategory = renderCategory(categoryLabelMap[categoryNameKey], emojisInCategory); const firstCategory = this.renderCategory(categoryLabelMap[categoryNameKey], emojisInCategory);
// Render the frequently used // Render the frequently used
const frequentlyUsedEmojis = this.getFrequentlyUsedEmojis(); const frequentlyUsedEmojis = this.getFrequentlyUsedEmojis();
let frequentlyUsedCatgegory = ''; let frequentlyUsedCatgegory = '';
if (frequentlyUsedEmojis.length > 0) { if (frequentlyUsedEmojis.length > 0) {
frequentlyUsedCatgegory = renderCategory('Frequently used', frequentlyUsedEmojis, { frequentlyUsedCatgegory = this.renderCategory('Frequently used', frequentlyUsedEmojis, {
menuListClass: 'frequent-emojis', menuListClass: 'frequent-emojis',
}); });
} }
...@@ -179,7 +160,7 @@ export default class AwardsHandler { ...@@ -179,7 +160,7 @@ export default class AwardsHandler {
} }
this.isAddingRemainingEmojiMenuCategories = true; this.isAddingRemainingEmojiMenuCategories = true;
const categoryMap = Emoji.getEmojiCategoryMap(); const categoryMap = this.emoji.getEmojiCategoryMap();
// Avoid the jank and render the remaining categories separately // Avoid the jank and render the remaining categories separately
// This will take more time, but makes UI more responsive // This will take more time, but makes UI more responsive
...@@ -191,7 +172,7 @@ export default class AwardsHandler { ...@@ -191,7 +172,7 @@ export default class AwardsHandler {
promiseChain.then(() => promiseChain.then(() =>
new Promise((resolve) => { new Promise((resolve) => {
const emojisInCategory = categoryMap[categoryNameKey]; const emojisInCategory = categoryMap[categoryNameKey];
const categoryMarkup = renderCategory( const categoryMarkup = this.renderCategory(
categoryLabelMap[categoryNameKey], categoryLabelMap[categoryNameKey],
emojisInCategory, emojisInCategory,
); );
...@@ -216,6 +197,25 @@ export default class AwardsHandler { ...@@ -216,6 +197,25 @@ export default class AwardsHandler {
}); });
} }
renderCategory(name, emojiList, opts = {}) {
return `
<h5 class="emoji-menu-title">
${name}
</h5>
<ul class="clearfix emoji-menu-list ${opts.menuListClass || ''}">
${emojiList.map(emojiName => `
<li class="emoji-menu-list-item">
<button class="emoji-menu-btn text-center js-emoji-btn" type="button">
${this.emoji.glEmojiTag(emojiName, {
sprite: true,
})}
</button>
</li>
`).join('\n')}
</ul>
`;
}
positionMenu($menu, $addBtn) { positionMenu($menu, $addBtn) {
const position = $addBtn.data('position'); const position = $addBtn.data('position');
// The menu could potentially be off-screen or in a hidden overflow element // The menu could potentially be off-screen or in a hidden overflow element
...@@ -234,7 +234,7 @@ export default class AwardsHandler { ...@@ -234,7 +234,7 @@ export default class AwardsHandler {
} }
addAward(votesBlock, awardUrl, emoji, checkMutuality, callback) { addAward(votesBlock, awardUrl, emoji, checkMutuality, callback) {
const normalizedEmoji = Emoji.normalizeEmojiName(emoji); const normalizedEmoji = this.emoji.normalizeEmojiName(emoji);
const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent(); const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent();
this.postEmoji($emojiButton, awardUrl, normalizedEmoji, () => { this.postEmoji($emojiButton, awardUrl, normalizedEmoji, () => {
this.addAwardToEmojiBar(votesBlock, normalizedEmoji, checkMutuality); this.addAwardToEmojiBar(votesBlock, normalizedEmoji, checkMutuality);
...@@ -249,7 +249,7 @@ export default class AwardsHandler { ...@@ -249,7 +249,7 @@ export default class AwardsHandler {
this.checkMutuality(votesBlock, emoji); this.checkMutuality(votesBlock, emoji);
} }
this.addEmojiToFrequentlyUsedList(emoji); this.addEmojiToFrequentlyUsedList(emoji);
const normalizedEmoji = Emoji.normalizeEmojiName(emoji); const normalizedEmoji = this.emoji.normalizeEmojiName(emoji);
const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent(); const $emojiButton = this.findEmojiIcon(votesBlock, normalizedEmoji).parent();
if ($emojiButton.length > 0) { if ($emojiButton.length > 0) {
if (this.isActive($emojiButton)) { if (this.isActive($emojiButton)) {
...@@ -374,7 +374,7 @@ export default class AwardsHandler { ...@@ -374,7 +374,7 @@ export default class AwardsHandler {
createAwardButtonForVotesBlock(votesBlock, emojiName) { createAwardButtonForVotesBlock(votesBlock, emojiName) {
const buttonHtml = ` const buttonHtml = `
<button class="btn award-control js-emoji-btn has-tooltip active" title="You" data-placement="bottom"> <button class="btn award-control js-emoji-btn has-tooltip active" title="You" data-placement="bottom">
${Emoji.glEmojiTag(emojiName)} ${this.emoji.glEmojiTag(emojiName)}
<span class="award-control-text js-counter">1</span> <span class="award-control-text js-counter">1</span>
</button> </button>
`; `;
...@@ -440,7 +440,7 @@ export default class AwardsHandler { ...@@ -440,7 +440,7 @@ export default class AwardsHandler {
} }
addEmojiToFrequentlyUsedList(emoji) { addEmojiToFrequentlyUsedList(emoji) {
if (Emoji.isEmojiNameValid(emoji)) { if (this.emoji.isEmojiNameValid(emoji)) {
this.frequentlyUsedEmojis = _.uniq(this.getFrequentlyUsedEmojis().concat(emoji)); this.frequentlyUsedEmojis = _.uniq(this.getFrequentlyUsedEmojis().concat(emoji));
Cookies.set('frequently_used_emojis', this.frequentlyUsedEmojis.join(','), { expires: 365 }); Cookies.set('frequently_used_emojis', this.frequentlyUsedEmojis.join(','), { expires: 365 });
} }
...@@ -450,7 +450,7 @@ export default class AwardsHandler { ...@@ -450,7 +450,7 @@ export default class AwardsHandler {
return this.frequentlyUsedEmojis || (() => { return this.frequentlyUsedEmojis || (() => {
const frequentlyUsedEmojis = _.uniq((Cookies.get('frequently_used_emojis') || '').split(',')); const frequentlyUsedEmojis = _.uniq((Cookies.get('frequently_used_emojis') || '').split(','));
this.frequentlyUsedEmojis = frequentlyUsedEmojis.filter( this.frequentlyUsedEmojis = frequentlyUsedEmojis.filter(
inputName => Emoji.isEmojiNameValid(inputName), inputName => this.emoji.isEmojiNameValid(inputName),
); );
return this.frequentlyUsedEmojis; return this.frequentlyUsedEmojis;
...@@ -493,7 +493,7 @@ export default class AwardsHandler { ...@@ -493,7 +493,7 @@ export default class AwardsHandler {
} }
findMatchingEmojiElements(query) { findMatchingEmojiElements(query) {
const emojiMatches = Emoji.filterEmojiNamesByAlias(query); const emojiMatches = this.emoji.filterEmojiNamesByAlias(query);
const $emojiElements = $('.emoji-menu-list:not(.frequent-emojis) [data-name]'); const $emojiElements = $('.emoji-menu-list:not(.frequent-emojis) [data-name]');
const $matchingElements = $emojiElements const $matchingElements = $emojiElements
.filter((i, elm) => emojiMatches.indexOf(elm.dataset.name) >= 0); .filter((i, elm) => emojiMatches.indexOf(elm.dataset.name) >= 0);
...@@ -507,3 +507,12 @@ export default class AwardsHandler { ...@@ -507,3 +507,12 @@ export default class AwardsHandler {
$('.emoji-menu').remove(); $('.emoji-menu').remove();
} }
} }
let awardsHandlerPromise = null;
export default function loadAwardsHandler(reload = false) {
if (!awardsHandlerPromise || reload) {
awardsHandlerPromise = import(/* webpackChunkName: 'emoji' */ './emoji')
.then(Emoji => new AwardsHandler(Emoji));
}
return awardsHandlerPromise;
}
import installCustomElements from 'document-register-element'; import installCustomElements from 'document-register-element';
import { emojiImageTag, emojiFallbackImageSrc } from '../emoji';
import isEmojiUnicodeSupported from '../emoji/support'; import isEmojiUnicodeSupported from '../emoji/support';
installCustomElements(window); installCustomElements(window);
...@@ -32,11 +31,19 @@ export default function installGlEmojiElement() { ...@@ -32,11 +31,19 @@ export default function installGlEmojiElement() {
// IE 11 doesn't like adding multiple at once :( // IE 11 doesn't like adding multiple at once :(
this.classList.add('emoji-icon'); this.classList.add('emoji-icon');
this.classList.add(fallbackSpriteClass); this.classList.add(fallbackSpriteClass);
} else if (hasImageFallback) {
this.innerHTML = emojiImageTag(name, fallbackSrc);
} else { } else {
const src = emojiFallbackImageSrc(name); import(/* webpackChunkName: 'emoji' */ '../emoji')
this.innerHTML = emojiImageTag(name, src); .then(({ emojiImageTag, emojiFallbackImageSrc }) => {
if (hasImageFallback) {
this.innerHTML = emojiImageTag(name, fallbackSrc);
} else {
const src = emojiFallbackImageSrc(name);
this.innerHTML = emojiImageTag(name, src);
}
})
.catch(() => {
// do nothing
});
} }
} }
}; };
......
import { validEmojiNames, glEmojiTag } from './emoji';
import glRegexp from './lib/utils/regexp'; import glRegexp from './lib/utils/regexp';
import AjaxCache from './lib/utils/ajax_cache'; import AjaxCache from './lib/utils/ajax_cache';
...@@ -373,7 +372,12 @@ class GfmAutoComplete { ...@@ -373,7 +372,12 @@ class GfmAutoComplete {
if (this.cachedData[at]) { if (this.cachedData[at]) {
this.loadData($input, at, this.cachedData[at]); this.loadData($input, at, this.cachedData[at]);
} else if (GfmAutoComplete.atTypeMap[at] === 'emojis') { } else if (GfmAutoComplete.atTypeMap[at] === 'emojis') {
this.loadData($input, at, validEmojiNames); import(/* webpackChunkName: 'emoji' */ './emoji')
.then(({ validEmojiNames, glEmojiTag }) => {
this.loadData($input, at, validEmojiNames);
GfmAutoComplete.glEmojiTag = glEmojiTag;
})
.catch(() => { this.isLoadingData[at] = false; });
} else { } else {
AjaxCache.retrieve(this.dataSources[GfmAutoComplete.atTypeMap[at]], true) AjaxCache.retrieve(this.dataSources[GfmAutoComplete.atTypeMap[at]], true)
.then((data) => { .then((data) => {
...@@ -428,12 +432,14 @@ GfmAutoComplete.atTypeMap = { ...@@ -428,12 +432,14 @@ GfmAutoComplete.atTypeMap = {
}; };
// Emoji // Emoji
GfmAutoComplete.glEmojiTag = null;
GfmAutoComplete.Emoji = { GfmAutoComplete.Emoji = {
templateFunction(name) { templateFunction(name) {
return `<li> // glEmojiTag helper is loaded on-demand in fetchData()
${name} ${glEmojiTag(name)} if (GfmAutoComplete.glEmojiTag) {
</li> return `<li>${name} ${GfmAutoComplete.glEmojiTag(name)}</li>`;
`; }
return `<li>${name}</li>`;
}, },
}; };
// Team Members // Team Members
......
...@@ -70,7 +70,7 @@ import './ajax_loading_spinner'; ...@@ -70,7 +70,7 @@ import './ajax_loading_spinner';
import './api'; import './api';
import './aside'; import './aside';
import './autosave'; import './autosave';
import AwardsHandler from './awards_handler'; import loadAwardsHandler from './awards_handler';
import './breakpoints'; import './breakpoints';
import './broadcast_message'; import './broadcast_message';
import './build'; import './build';
...@@ -355,7 +355,7 @@ $(function () { ...@@ -355,7 +355,7 @@ $(function () {
$window.off('resize.app').on('resize.app', function () { $window.off('resize.app').on('resize.app', function () {
return fitSidebarForSize(); return fitSidebarForSize();
}); });
gl.awardsHandler = new AwardsHandler(); loadAwardsHandler();
new Aside(); new Aside();
gl.utils.renderTimeago(); gl.utils.renderTimeago();
......
...@@ -18,6 +18,7 @@ import 'vendor/jquery.caret'; // required by jquery.atwho ...@@ -18,6 +18,7 @@ import 'vendor/jquery.caret'; // required by jquery.atwho
import 'vendor/jquery.atwho'; import 'vendor/jquery.atwho';
import AjaxCache from '~/lib/utils/ajax_cache'; import AjaxCache from '~/lib/utils/ajax_cache';
import CommentTypeToggle from './comment_type_toggle'; import CommentTypeToggle from './comment_type_toggle';
import loadAwardsHandler from './awards_handler';
import './autosave'; import './autosave';
import './dropzone_input'; import './dropzone_input';
import './task_list'; import './task_list';
...@@ -291,8 +292,13 @@ export default class Notes { ...@@ -291,8 +292,13 @@ export default class Notes {
if ('emoji_award' in noteEntity.commands_changes) { if ('emoji_award' in noteEntity.commands_changes) {
votesBlock = $('.js-awards-block').eq(0); votesBlock = $('.js-awards-block').eq(0);
gl.awardsHandler.addAwardToEmojiBar(votesBlock, noteEntity.commands_changes.emoji_award);
return gl.awardsHandler.scrollToAwards(); loadAwardsHandler().then((awardsHandler) => {
awardsHandler.addAwardToEmojiBar(votesBlock, noteEntity.commands_changes.emoji_award);
awardsHandler.scrollToAwards();
}).catch(() => {
// ignore
});
} }
} }
} }
......
/**
* This is the first script loaded by webpack's runtime. It is used to manually configure
* config.output.publicPath to account for relative_url_root or CDN settings which cannot be
* baked-in to our webpack bundles.
*/
if (gon && gon.webpack_public_path) {
__webpack_public_path__ = gon.webpack_public_path; // eslint-disable-line
}
...@@ -11,20 +11,29 @@ module WebpackHelper ...@@ -11,20 +11,29 @@ module WebpackHelper
paths = Webpack::Rails::Manifest.asset_paths(source) paths = Webpack::Rails::Manifest.asset_paths(source)
if extension if extension
paths = paths.select { |p| p.ends_with? ".#{extension}" } paths.select! { |p| p.ends_with? ".#{extension}" }
end end
# include full webpack-dev-server url for rspec tests running locally force_host = webpack_public_host
if force_host
paths.map! { |p| "#{force_host}#{p}" }
end
paths
end
def webpack_public_host
if Rails.env.test? && Rails.configuration.webpack.dev_server.enabled if Rails.env.test? && Rails.configuration.webpack.dev_server.enabled
host = Rails.configuration.webpack.dev_server.host host = Rails.configuration.webpack.dev_server.host
port = Rails.configuration.webpack.dev_server.port port = Rails.configuration.webpack.dev_server.port
protocol = Rails.configuration.webpack.dev_server.https ? 'https' : 'http' protocol = Rails.configuration.webpack.dev_server.https ? 'https' : 'http'
"#{protocol}://#{host}:#{port}"
paths.map! do |p| else
"#{protocol}://#{host}:#{port}#{p}" ActionController::Base.asset_host.try(:chomp, '/')
end
end end
end
paths def webpack_public_path
"#{webpack_public_host}/#{Rails.application.config.webpack.public_path}/"
end end
end end
...@@ -38,7 +38,7 @@ ...@@ -38,7 +38,7 @@
= Gon::Base.render_data = Gon::Base.render_data
= webpack_bundle_tag "runtime" = webpack_bundle_tag "webpack_runtime"
= webpack_bundle_tag "common" = webpack_bundle_tag "common"
= webpack_bundle_tag "locale" = webpack_bundle_tag "locale"
= webpack_bundle_tag "main" = webpack_bundle_tag "main"
......
---
title: Enable support for webpack code-splitting by dynamically setting publicPath
at runtime
merge_request: 12032
author:
...@@ -71,6 +71,7 @@ var config = { ...@@ -71,6 +71,7 @@ var config = {
vue_merge_request_widget: './vue_merge_request_widget/index.js', vue_merge_request_widget: './vue_merge_request_widget/index.js',
test: './test.js', test: './test.js',
peek: './peek.js', peek: './peek.js',
webpack_runtime: './webpack.js',
}, },
output: { output: {
...@@ -190,7 +191,7 @@ var config = { ...@@ -190,7 +191,7 @@ var config = {
// create cacheable common library bundles // create cacheable common library bundles
new webpack.optimize.CommonsChunkPlugin({ new webpack.optimize.CommonsChunkPlugin({
names: ['main', 'locale', 'common', 'runtime'], names: ['main', 'locale', 'common', 'webpack_runtime'],
}), }),
], ],
...@@ -245,7 +246,6 @@ if (IS_DEV_SERVER) { ...@@ -245,7 +246,6 @@ if (IS_DEV_SERVER) {
hot: DEV_SERVER_LIVERELOAD, hot: DEV_SERVER_LIVERELOAD,
inline: DEV_SERVER_LIVERELOAD inline: DEV_SERVER_LIVERELOAD
}; };
config.output.publicPath = '//' + DEV_SERVER_HOST + ':' + DEV_SERVER_PORT + config.output.publicPath;
config.plugins.push( config.plugins.push(
// watch node_modules for changes if we encounter a missing module compile error // watch node_modules for changes if we encounter a missing module compile error
new WatchMissingNodeModulesPlugin(path.join(ROOT_PATH, 'node_modules')) new WatchMissingNodeModulesPlugin(path.join(ROOT_PATH, 'node_modules'))
......
...@@ -2,11 +2,14 @@ ...@@ -2,11 +2,14 @@
module Gitlab module Gitlab
module GonHelper module GonHelper
include WebpackHelper
def add_gon_variables def add_gon_variables
gon.api_version = 'v4' gon.api_version = 'v4'
gon.default_avatar_url = URI.join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s gon.default_avatar_url = URI.join(Gitlab.config.gitlab.url, ActionController::Base.helpers.image_path('no_avatar.png')).to_s
gon.max_file_size = current_application_settings.max_attachment_size gon.max_file_size = current_application_settings.max_attachment_size
gon.asset_host = ActionController::Base.asset_host gon.asset_host = ActionController::Base.asset_host
gon.webpack_public_path = webpack_public_path
gon.relative_url_root = Gitlab.config.gitlab.relative_url_root gon.relative_url_root = Gitlab.config.gitlab.relative_url_root
gon.shortcuts_path = help_page_path('shortcuts') gon.shortcuts_path = help_page_path('shortcuts')
gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class gon.user_color_scheme = Gitlab::ColorSchemes.for_user(current_user).css_class
......
/* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, max-len */ /* eslint-disable space-before-function-paren, no-var, one-var, one-var-declaration-per-line, no-unused-expressions, comma-dangle, new-parens, no-unused-vars, quotes, jasmine/no-spec-dupes, prefer-template, max-len */
import Cookies from 'js-cookie'; import Cookies from 'js-cookie';
import AwardsHandler from '~/awards_handler'; import loadAwardsHandler from '~/awards_handler';
import '~/lib/utils/common_utils'; import '~/lib/utils/common_utils';
...@@ -26,14 +26,13 @@ import '~/lib/utils/common_utils'; ...@@ -26,14 +26,13 @@ import '~/lib/utils/common_utils';
describe('AwardsHandler', function() { describe('AwardsHandler', function() {
preloadFixtures('issues/issue_with_comment.html.raw'); preloadFixtures('issues/issue_with_comment.html.raw');
beforeEach(function() { beforeEach(function(done) {
loadFixtures('issues/issue_with_comment.html.raw'); loadFixtures('issues/issue_with_comment.html.raw');
awardsHandler = new AwardsHandler; loadAwardsHandler(true).then((obj) => {
spyOn(awardsHandler, 'postEmoji').and.callFake((function(_this) { awardsHandler = obj;
return function(button, url, emoji, cb) { spyOn(awardsHandler, 'postEmoji').and.callFake((button, url, emoji, cb) => cb());
return cb(); done();
}; }).catch(fail);
})(this));
let isEmojiMenuBuilt = false; let isEmojiMenuBuilt = false;
openAndWaitForEmojiMenu = function() { openAndWaitForEmojiMenu = function() {
......
...@@ -265,6 +265,15 @@ babel-core@^6.22.1, babel-core@^6.23.0: ...@@ -265,6 +265,15 @@ babel-core@^6.22.1, babel-core@^6.23.0:
slash "^1.0.0" slash "^1.0.0"
source-map "^0.5.0" source-map "^0.5.0"
babel-eslint@^7.2.1:
version "7.2.1"
resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.1.tgz#079422eb73ba811e3ca0865ce87af29327f8c52f"
dependencies:
babel-code-frame "^6.22.0"
babel-traverse "^6.23.1"
babel-types "^6.23.0"
babylon "^6.16.1"
babel-generator@^6.18.0, babel-generator@^6.23.0: babel-generator@^6.18.0, babel-generator@^6.23.0:
version "6.23.0" version "6.23.0"
resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.23.0.tgz#6b8edab956ef3116f79d8c84c5a3c05f32a74bc5" resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.23.0.tgz#6b8edab956ef3116f79d8c84c5a3c05f32a74bc5"
...@@ -816,10 +825,14 @@ babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23 ...@@ -816,10 +825,14 @@ babel-types@^6.18.0, babel-types@^6.19.0, babel-types@^6.22.0, babel-types@^6.23
lodash "^4.2.0" lodash "^4.2.0"
to-fast-properties "^1.0.1" to-fast-properties "^1.0.1"
babylon@^6.11.0, babylon@^6.13.0, babylon@^6.15.0: babylon@^6.11.0:
version "6.15.0" version "6.15.0"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e" resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e"
babylon@^6.13.0, babylon@^6.15.0, babylon@^6.16.1:
version "6.16.1"
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.16.1.tgz#30c5a22f481978a9e7f8cdfdf496b11d94b404d3"
backo2@1.0.2: backo2@1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947" resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment