Change how CDN_HOST is passed down to make assets build reproducible (#14381)

* Change how CDN_HOST is passed down to make assets build reproducible

* Change webpacker/webpack configuration to dynamically load publicPath based on meta header

* Fix embedded layout missing the cdn-host meta header
This commit is contained in:
ThibG 2020-10-13 01:19:35 +02:00 committed by GitHub
parent 53b22d247f
commit 4c45b43cb8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 46 additions and 24 deletions

View File

@ -1,8 +1,7 @@
import React from 'react'; import React from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light'; import unicodeMapping from '../features/emoji/emoji_unicode_mapping_light';
import { assetHost } from 'mastodon/utils/config';
const assetHost = process.env.CDN_HOST || '';
export default class AutosuggestEmoji extends React.PureComponent { export default class AutosuggestEmoji extends React.PureComponent {

View File

@ -7,6 +7,7 @@ import classNames from 'classnames';
import ImmutablePropTypes from 'react-immutable-proptypes'; import ImmutablePropTypes from 'react-immutable-proptypes';
import detectPassiveEvents from 'detect-passive-events'; import detectPassiveEvents from 'detect-passive-events';
import { buildCustomEmojis, categoriesFromEmojis } from '../../emoji/emoji'; import { buildCustomEmojis, categoriesFromEmojis } from '../../emoji/emoji';
import { assetHost } from 'mastodon/utils/config';
const messages = defineMessages({ const messages = defineMessages({
emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' }, emoji: { id: 'emoji_button.label', defaultMessage: 'Insert emoji' },
@ -25,7 +26,6 @@ const messages = defineMessages({
flags: { id: 'emoji_button.flags', defaultMessage: 'Flags' }, flags: { id: 'emoji_button.flags', defaultMessage: 'Flags' },
}); });
const assetHost = process.env.CDN_HOST || '';
let EmojiPicker, Emoji; // load asynchronously let EmojiPicker, Emoji; // load asynchronously
const backgroundImageFn = () => `${assetHost}/emoji/sheet_10.png`; const backgroundImageFn = () => `${assetHost}/emoji/sheet_10.png`;

View File

@ -1,11 +1,10 @@
import { autoPlayGif } from '../../initial_state'; import { autoPlayGif } from '../../initial_state';
import unicodeMapping from './emoji_unicode_mapping_light'; import unicodeMapping from './emoji_unicode_mapping_light';
import { assetHost } from 'mastodon/utils/config';
import Trie from 'substring-trie'; import Trie from 'substring-trie';
const trie = new Trie(Object.keys(unicodeMapping)); const trie = new Trie(Object.keys(unicodeMapping));
const assetHost = process.env.CDN_HOST || '';
// Convert to file names from emojis. (For different variation selector emojis) // Convert to file names from emojis. (For different variation selector emojis)
const emojiFilenames = (emojis) => { const emojiFilenames = (emojis) => {
return emojis.map(v => unicodeMapping[v].filename); return emojis.map(v => unicodeMapping[v].filename);

View File

@ -15,6 +15,7 @@ import EmojiPickerDropdown from 'mastodon/features/compose/containers/emoji_pick
import AnimatedNumber from 'mastodon/components/animated_number'; import AnimatedNumber from 'mastodon/components/animated_number';
import TransitionMotion from 'react-motion/lib/TransitionMotion'; import TransitionMotion from 'react-motion/lib/TransitionMotion';
import spring from 'react-motion/lib/spring'; import spring from 'react-motion/lib/spring';
import { assetHost } from 'mastodon/utils/config';
const messages = defineMessages({ const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' }, close: { id: 'lightbox.close', defaultMessage: 'Close' },
@ -153,8 +154,6 @@ class Content extends ImmutablePureComponent {
} }
const assetHost = process.env.CDN_HOST || '';
class Emoji extends React.PureComponent { class Emoji extends React.PureComponent {
static propTypes = { static propTypes = {

View File

@ -20,6 +20,7 @@ import GIFV from 'mastodon/components/gifv';
import { me } from 'mastodon/initial_state'; import { me } from 'mastodon/initial_state';
import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js'; import tesseractCorePath from 'tesseract.js-core/tesseract-core.wasm.js';
import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js'; import tesseractWorkerPath from 'tesseract.js/dist/worker.min.js';
import { assetHost } from 'mastodon/utils/config';
const messages = defineMessages({ const messages = defineMessages({
close: { id: 'lightbox.close', defaultMessage: 'Close' }, close: { id: 'lightbox.close', defaultMessage: 'Close' },
@ -50,8 +51,6 @@ const removeExtraLineBreaks = str => str.replace(/\n\n/g, '******')
.replace(/\n/g, ' ') .replace(/\n/g, ' ')
.replace(/\*\*\*\*\*\*/g, '\n\n'); .replace(/\*\*\*\*\*\*/g, '\n\n');
const assetHost = process.env.CDN_HOST || '';
class ImageLoader extends React.PureComponent { class ImageLoader extends React.PureComponent {
static propTypes = { static propTypes = {

View File

@ -0,0 +1,10 @@
import ready from '../ready';
export let assetHost = '';
ready(() => {
const cdnHost = document.querySelector('meta[name=cdn-host]');
if (cdnHost) {
assetHost = cdnHost.content || '';
}
});

View File

@ -1,3 +1,4 @@
import './public-path';
import loadPolyfills from '../mastodon/load_polyfills'; import loadPolyfills from '../mastodon/load_polyfills';
import { start } from '../mastodon/common'; import { start } from '../mastodon/common';

View File

@ -1,3 +1,4 @@
import './public-path';
import { delegate } from '@rails/ujs'; import { delegate } from '@rails/ujs';
import ready from '../mastodon/ready'; import ready from '../mastodon/ready';

View File

@ -1,3 +1,4 @@
import './public-path';
import loadPolyfills from '../mastodon/load_polyfills'; import loadPolyfills from '../mastodon/load_polyfills';
import { start } from '../mastodon/common'; import { start } from '../mastodon/common';

View File

@ -1,3 +1,4 @@
import './public-path';
import ready from '../mastodon/ready'; import ready from '../mastodon/ready';
ready(() => { ready(() => {

View File

@ -0,0 +1,21 @@
// Dynamically set webpack's loading path depending on a meta header, in order
// to share the same assets regardless of instance configuration.
// See https://webpack.js.org/guides/public-path/#on-the-fly
function removeOuterSlashes(string) {
return string.replace(/^\/*/, '').replace(/\/*$/, '');
}
function formatPublicPath(host = '', path = '') {
let formattedHost = removeOuterSlashes(host);
if (formattedHost && !/^http/i.test(formattedHost)) {
formattedHost = `//${formattedHost}`;
}
const formattedPath = removeOuterSlashes(path);
return `${formattedHost}/${formattedPath}/`;
}
const cdnHost = document.querySelector('meta[name=cdn-host]');
// eslint-disable-next-line camelcase, no-undef, no-unused-vars
__webpack_public_path__ = formatPublicPath(cdnHost ? cdnHost.content : '', process.env.PUBLIC_OUTPUT_PATH);

View File

@ -1,3 +1,4 @@
import './public-path';
import escapeTextContentForBrowser from 'escape-html'; import escapeTextContentForBrowser from 'escape-html';
import loadPolyfills from '../mastodon/load_polyfills'; import loadPolyfills from '../mastodon/load_polyfills';
import ready from '../mastodon/ready'; import ready from '../mastodon/ready';

View File

@ -1,3 +1,4 @@
import './public-path';
import loadPolyfills from '../mastodon/load_polyfills'; import loadPolyfills from '../mastodon/load_polyfills';
import { start } from '../mastodon/common'; import { start } from '../mastodon/common';

View File

@ -6,6 +6,7 @@
- if cdn_host? - if cdn_host?
%link{ rel: 'dns-prefetch', href: cdn_host }/ %link{ rel: 'dns-prefetch', href: cdn_host }/
%meta{ name: 'cdn-host', content: cdn_host }/
- if storage_host? - if storage_host?
%link{ rel: 'dns-prefetch', href: storage_host }/ %link{ rel: 'dns-prefetch', href: storage_host }/

View File

@ -6,6 +6,7 @@
- if cdn_host? - if cdn_host?
%link{ rel: 'dns-prefetch', href: cdn_host }/ %link{ rel: 'dns-prefetch', href: cdn_host }/
%meta{ name: 'cdn-host', content: cdn_host }/
- if storage_host? - if storage_host?
%link{ rel: 'dns-prefetch', href: storage_host }/ %link{ rel: 'dns-prefetch', href: storage_host }/

View File

@ -11,30 +11,17 @@ const settings = safeLoad(readFileSync(configPath), 'utf8')[env.RAILS_ENV || env
const themePath = resolve('config', 'themes.yml'); const themePath = resolve('config', 'themes.yml');
const themes = safeLoad(readFileSync(themePath), 'utf8'); const themes = safeLoad(readFileSync(themePath), 'utf8');
function removeOuterSlashes(string) {
return string.replace(/^\/*/, '').replace(/\/*$/, '');
}
function formatPublicPath(host = '', path = '') {
let formattedHost = removeOuterSlashes(host);
if (formattedHost && !/^http/i.test(formattedHost)) {
formattedHost = `//${formattedHost}`;
}
const formattedPath = removeOuterSlashes(path);
return `${formattedHost}/${formattedPath}/`;
}
const output = { const output = {
path: resolve('public', settings.public_output_path), path: resolve('public', settings.public_output_path),
publicPath: formatPublicPath(env.CDN_HOST, settings.public_output_path), publicPath: `/${settings.public_output_path}/`,
}; };
module.exports = { module.exports = {
settings, settings,
themes, themes,
env: { env: {
CDN_HOST: env.CDN_HOST,
NODE_ENV: env.NODE_ENV, NODE_ENV: env.NODE_ENV,
PUBLIC_OUTPUT_PATH: settings.public_output_path,
}, },
output, output,
}; };