diff --git a/app/soapbox/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap b/app/soapbox/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap index 6bbb1eb74..1ab178e15 100644 --- a/app/soapbox/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap +++ b/app/soapbox/components/__tests__/__snapshots__/autosuggest_emoji-test.js.snap @@ -20,11 +20,7 @@ exports[` renders native emoji 1`] = ` ๐Ÿ’™ :foobar: diff --git a/app/soapbox/components/__tests__/__snapshots__/emoji_selector-test.js.snap b/app/soapbox/components/__tests__/__snapshots__/emoji_selector-test.js.snap index d009a5551..0ff8f9961 100644 --- a/app/soapbox/components/__tests__/__snapshots__/emoji_selector-test.js.snap +++ b/app/soapbox/components/__tests__/__snapshots__/emoji_selector-test.js.snap @@ -15,7 +15,7 @@ exports[` renders correctly 1`] = ` className="emoji-react-selector__emoji" dangerouslySetInnerHTML={ Object { - "__html": "\\"๐Ÿ‘\\"", + "__html": "\\"๐Ÿ‘\\"", } } onClick={[Function]} @@ -26,7 +26,7 @@ exports[` renders correctly 1`] = ` className="emoji-react-selector__emoji" dangerouslySetInnerHTML={ Object { - "__html": "\\"โค\\"", + "__html": "\\"โค\\"", } } onClick={[Function]} @@ -37,7 +37,7 @@ exports[` renders correctly 1`] = ` className="emoji-react-selector__emoji" dangerouslySetInnerHTML={ Object { - "__html": "\\"๐Ÿ˜†\\"", + "__html": "\\"๐Ÿ˜†\\"", } } onClick={[Function]} @@ -48,7 +48,7 @@ exports[` renders correctly 1`] = ` className="emoji-react-selector__emoji" dangerouslySetInnerHTML={ Object { - "__html": "\\"๐Ÿ˜ฎ\\"", + "__html": "\\"๐Ÿ˜ฎ\\"", } } onClick={[Function]} @@ -59,7 +59,7 @@ exports[` renders correctly 1`] = ` className="emoji-react-selector__emoji" dangerouslySetInnerHTML={ Object { - "__html": "\\"๐Ÿ˜ข\\"", + "__html": "\\"๐Ÿ˜ข\\"", } } onClick={[Function]} @@ -70,7 +70,7 @@ exports[` renders correctly 1`] = ` className="emoji-react-selector__emoji" dangerouslySetInnerHTML={ Object { - "__html": "\\"๐Ÿ˜ฉ\\"", + "__html": "\\"๐Ÿ˜ฉ\\"", } } onClick={[Function]} diff --git a/app/soapbox/components/autosuggest_emoji.js b/app/soapbox/components/autosuggest_emoji.js index da2df72a3..188dc6c0e 100644 --- a/app/soapbox/components/autosuggest_emoji.js +++ b/app/soapbox/components/autosuggest_emoji.js @@ -1,6 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light'; +import { joinPublicPath } from 'soapbox/utils/static'; export default class AutosuggestEmoji extends React.PureComponent { @@ -21,7 +22,7 @@ export default class AutosuggestEmoji extends React.PureComponent { return null; } - url = require(`twemoji/assets/svg/${mapping.filename}.svg`); + url = joinPublicPath(`packs/emoji/${mapping.filename}.svg`); } return ( diff --git a/app/soapbox/features/compose/components/emoji_picker_dropdown.js b/app/soapbox/features/compose/components/emoji_picker_dropdown.js index 9823978c9..29d3270c9 100644 --- a/app/soapbox/features/compose/components/emoji_picker_dropdown.js +++ b/app/soapbox/features/compose/components/emoji_picker_dropdown.js @@ -7,6 +7,7 @@ import classNames from 'classnames'; import ImmutablePropTypes from 'react-immutable-proptypes'; import { supportsPassiveEvents } from 'detect-passive-events'; import { buildCustomEmojis } from '../../emoji/emoji'; +import { joinPublicPath } from 'soapbox/utils/static'; const messages = defineMessages({ emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' }, @@ -357,7 +358,7 @@ class EmojiPickerDropdown extends React.PureComponent { ๐Ÿ˜‚ diff --git a/app/soapbox/features/emoji/__tests__/emoji-test.js b/app/soapbox/features/emoji/__tests__/emoji-test.js index ce8d4e2a8..f1374e8c1 100644 --- a/app/soapbox/features/emoji/__tests__/emoji-test.js +++ b/app/soapbox/features/emoji/__tests__/emoji-test.js @@ -22,23 +22,23 @@ describe('emoji', () => { it('does unicode', () => { expect(emojify('\uD83D\uDC69\u200D\uD83D\uDC69\u200D\uD83D\uDC66\u200D\uD83D\uDC66')).toEqual( - '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ'); + '๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆโ€๐Ÿ‘ฆ'); expect(emojify('๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง')).toEqual( - '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง'); - expect(emojify('๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ')).toEqual('๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ'); + '๐Ÿ‘จโ€๐Ÿ‘ฉโ€๐Ÿ‘งโ€๐Ÿ‘ง'); + expect(emojify('๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ')).toEqual('๐Ÿ‘ฉโ€๐Ÿ‘ฉโ€๐Ÿ‘ฆ'); expect(emojify('\u2757')).toEqual( - 'โ—'); + 'โ—'); }); it('does multiple unicode', () => { expect(emojify('\u2757 #\uFE0F\u20E3')).toEqual( - 'โ— #๏ธโƒฃ'); + 'โ— #๏ธโƒฃ'); expect(emojify('\u2757#\uFE0F\u20E3')).toEqual( - 'โ—#๏ธโƒฃ'); + 'โ—#๏ธโƒฃ'); expect(emojify('\u2757 #\uFE0F\u20E3 \u2757')).toEqual( - 'โ— #๏ธโƒฃ โ—'); + 'โ— #๏ธโƒฃ โ—'); expect(emojify('foo \u2757 #\uFE0F\u20E3 bar')).toEqual( - 'foo โ— #๏ธโƒฃ bar'); + 'foo โ— #๏ธโƒฃ bar'); }); it('ignores unicode inside of tags', () => { @@ -46,16 +46,16 @@ describe('emoji', () => { }); it('does multiple emoji properly (issue 5188)', () => { - expect(emojify('๐Ÿ‘Œ๐ŸŒˆ๐Ÿ’•')).toEqual('๐Ÿ‘Œ๐ŸŒˆ๐Ÿ’•'); - expect(emojify('๐Ÿ‘Œ ๐ŸŒˆ ๐Ÿ’•')).toEqual('๐Ÿ‘Œ ๐ŸŒˆ ๐Ÿ’•'); + expect(emojify('๐Ÿ‘Œ๐ŸŒˆ๐Ÿ’•')).toEqual('๐Ÿ‘Œ๐ŸŒˆ๐Ÿ’•'); + expect(emojify('๐Ÿ‘Œ ๐ŸŒˆ ๐Ÿ’•')).toEqual('๐Ÿ‘Œ ๐ŸŒˆ ๐Ÿ’•'); }); it('does an emoji that has no shortcode', () => { - expect(emojify('๐Ÿ‘โ€๐Ÿ—จ')).toEqual('๐Ÿ‘โ€๐Ÿ—จ'); + expect(emojify('๐Ÿ‘โ€๐Ÿ—จ')).toEqual('๐Ÿ‘โ€๐Ÿ—จ'); }); it('does an emoji whose filename is irregular', () => { - expect(emojify('โ†™๏ธ')).toEqual('โ†™๏ธ'); + expect(emojify('โ†™๏ธ')).toEqual('โ†™๏ธ'); }); it('avoid emojifying on invisible text', () => { @@ -67,16 +67,16 @@ describe('emoji', () => { it('avoid emojifying on invisible text with nested tags', () => { expect(emojify('๐Ÿ˜‡')) - .toEqual('๐Ÿ˜‡'); + .toEqual('๐Ÿ˜‡'); expect(emojify('๐Ÿ˜‡')) - .toEqual('๐Ÿ˜‡'); + .toEqual('๐Ÿ˜‡'); expect(emojify('๐Ÿ˜‡')) - .toEqual('๐Ÿ˜‡'); + .toEqual('๐Ÿ˜‡'); }); it('skips the textual presentation VS15 character', () => { expect(emojify('โœด๏ธŽ')) // This is U+2734 EIGHT POINTED BLACK STAR then U+FE0E VARIATION SELECTOR-15 - .toEqual('โœด'); + .toEqual('โœด'); }); }); }); diff --git a/app/soapbox/features/emoji/emoji.js b/app/soapbox/features/emoji/emoji.js index fe1029c59..e43f67ac7 100644 --- a/app/soapbox/features/emoji/emoji.js +++ b/app/soapbox/features/emoji/emoji.js @@ -1,5 +1,6 @@ import unicodeMapping from './emoji_unicode_mapping_light'; import Trie from 'substring-trie'; +import { joinPublicPath } from 'soapbox/utils/static'; const trie = new Trie(Object.keys(unicodeMapping)); @@ -60,7 +61,7 @@ const emojify = (str, customEmojis = {}, autoplay = false) => { } else { // matched to unicode emoji const { filename, shortCode } = unicodeMapping[match]; const title = shortCode ? `:${shortCode}:` : ''; - const src = require(`twemoji/assets/svg/${filename}.svg`); + const src = joinPublicPath(`packs/emoji/${filename}.svg`); replacement = `${match}`; rend = i + match.length; // If the matched character was followed by VS15 (for selecting text presentation), skip it. diff --git a/app/soapbox/utils/static.js b/app/soapbox/utils/static.js new file mode 100644 index 000000000..e9fcd7001 --- /dev/null +++ b/app/soapbox/utils/static.js @@ -0,0 +1,11 @@ +/** + * Static: functions related to static files. + * @module soapbox/utils/static + */ + +import { join } from 'path'; +import { FE_SUBDIRECTORY } from 'soapbox/build_config'; + +export const joinPublicPath = (...paths) => { + return join(FE_SUBDIRECTORY, ...paths); +}; diff --git a/webpack/production.js b/webpack/production.js index cccfc4163..0e1643fee 100644 --- a/webpack/production.js +++ b/webpack/production.js @@ -1,11 +1,15 @@ // Note: You must restart bin/webpack-dev-server for changes to take effect console.log('Running in production mode'); // eslint-disable-line no-console +const { join } = require('path'); const { merge } = require('webpack-merge'); const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer'); const OfflinePlugin = require('@lcdp/offline-plugin'); const sharedConfig = require('./shared'); +const { FE_SUBDIRECTORY } = require(join(__dirname, '..', 'app', 'soapbox', 'build_config')); +const joinPublicPath = (...paths) => join(FE_SUBDIRECTORY, ...paths); + module.exports = merge(sharedConfig, { mode: 'production', devtool: 'source-map', @@ -26,28 +30,32 @@ module.exports = merge(sharedConfig, { caches: { main: [':rest:'], additional: [ - 'packs/emoji/1f602-*.svg', // used for emoji picker dropdown - 'packs/images/32-*.png', // used in emoji-mart - - // Default emoji reacts - 'packs/emoji/1f44d-*.svg', // Thumbs up - 'packs/emoji/2764-*.svg', // Heart - 'packs/emoji/1f606-*.svg', // Laughing - 'packs/emoji/1f62e-*.svg', // Surprised - 'packs/emoji/1f622-*.svg', // Crying - 'packs/emoji/1f629-*.svg', // Weary - 'packs/emoji/1f621-*.svg', // Angry (Spinster) + ':externals:', + 'packs/images/32-*.png', // used in emoji-mart ], optional: [ '**/locale_*.js', // don't fetch every locale; the user only needs one '**/*_polyfills-*.js', // the user may not need polyfills '**/*.chunk.js', // only cache chunks when needed + '**/*.chunk.css', '**/*.woff2', // the user may have system-fonts enabled // images can be cached on-demand '**/*.png', '**/*.svg', ], }, + externals: [ + joinPublicPath('packs/emoji/1f602.svg'), // used for emoji picker dropdown + + // Default emoji reacts + joinPublicPath('packs/emoji/1f44d.svg'), // Thumbs up + joinPublicPath('packs/emoji/2764.svg'), // Heart + joinPublicPath('packs/emoji/1f606.svg'), // Laughing + joinPublicPath('packs/emoji/1f62e.svg'), // Surprised + joinPublicPath('packs/emoji/1f622.svg'), // Crying + joinPublicPath('packs/emoji/1f629.svg'), // Weary + joinPublicPath('packs/emoji/1f621.svg'), // Angry (Spinster) + ], excludes: [ '**/*.gz', '**/*.map', @@ -69,12 +77,16 @@ module.exports = merge(sharedConfig, { // https://github.com/bromite/bromite/issues/1294 'index.html', '404.html', + 'assets-manifest.json', + // It would be nice to serve these, but they bloat up sw.js + 'packs/images/crypto/**/*', + 'packs/emoji/**/*', ], - // ServiceWorker: { - // entry: join(__dirname, '../app/soapbox/service_worker/entry.js'), - // cacheName: 'soapbox', - // minify: true, - // }, + ServiceWorker: { + // entry: join(__dirname, '../app/soapbox/service_worker/entry.js'), + // cacheName: 'soapbox', + minify: true, + }, safeToUseOptionalCaches: true, }), ], diff --git a/webpack/shared.js b/webpack/shared.js index 0c4bd856e..fd01df7be 100644 --- a/webpack/shared.js +++ b/webpack/shared.js @@ -88,6 +88,9 @@ module.exports = { new HtmlWebpackHarddiskPlugin(), new CopyPlugin({ patterns: [{ + from: join(__dirname, '../node_modules/twemoji/assets/svg'), + to: join(output.path, 'packs/emoji'), + }, { from: join(__dirname, '../app/instance'), to: join(output.path, 'instance'), }],