From f5bf5ebb82e3af420dcd23d602b1be6cc86838e1 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Wed, 3 May 2017 02:04:16 +0200 Subject: Replace sprockets/browserify with Webpack (#2617) * Replace browserify with webpack * Add react-intl-translations-manager * Do not minify in development, add offline-plugin for ServiceWorker background cache updates * Adjust tests and dependencies * Fix production deployments * Fix tests * More optimizations * Improve travis cache for npm stuff * Re-run travis * Add back support for custom.scss as before * Remove offline-plugin and babili * Fix issue with Immutable.List().unshift(...values) not working as expected * Make travis load schema instead of running all migrations in sequence * Fix missing React import in WarningContainer. Optimize rendering performance by using ImmutablePureComponent instead of React.PureComponent. ImmutablePureComponent uses Immutable.is() to compare props. Replace dynamic callback bindings in * Add react definitions to places that use JSX * Add Procfile.dev for running rails, webpack and streaming API at the same time --- .../components/containers/account_container.jsx | 50 ---- .../javascripts/components/containers/mastodon.jsx | 320 --------------------- .../components/containers/status_container.jsx | 117 -------- 3 files changed, 487 deletions(-) delete mode 100644 app/assets/javascripts/components/containers/account_container.jsx delete mode 100644 app/assets/javascripts/components/containers/mastodon.jsx delete mode 100644 app/assets/javascripts/components/containers/status_container.jsx (limited to 'app/assets/javascripts/components/containers') diff --git a/app/assets/javascripts/components/containers/account_container.jsx b/app/assets/javascripts/components/containers/account_container.jsx deleted file mode 100644 index 3c30be715..000000000 --- a/app/assets/javascripts/components/containers/account_container.jsx +++ /dev/null @@ -1,50 +0,0 @@ -import { connect } from 'react-redux'; -import { makeGetAccount } from '../selectors'; -import Account from '../components/account'; -import { - followAccount, - unfollowAccount, - blockAccount, - unblockAccount, - muteAccount, - unmuteAccount, -} from '../actions/accounts'; - -const makeMapStateToProps = () => { - const getAccount = makeGetAccount(); - - const mapStateToProps = (state, props) => ({ - account: getAccount(state, props.id), - me: state.getIn(['meta', 'me']) - }); - - return mapStateToProps; -}; - -const mapDispatchToProps = (dispatch) => ({ - onFollow (account) { - if (account.getIn(['relationship', 'following'])) { - dispatch(unfollowAccount(account.get('id'))); - } else { - dispatch(followAccount(account.get('id'))); - } - }, - - onBlock (account) { - if (account.getIn(['relationship', 'blocking'])) { - dispatch(unblockAccount(account.get('id'))); - } else { - dispatch(blockAccount(account.get('id'))); - } - }, - - onMute (account) { - if (account.getIn(['relationship', 'muting'])) { - dispatch(unmuteAccount(account.get('id'))); - } else { - dispatch(muteAccount(account.get('id'))); - } - } -}); - -export default connect(makeMapStateToProps, mapDispatchToProps)(Account); diff --git a/app/assets/javascripts/components/containers/mastodon.jsx b/app/assets/javascripts/components/containers/mastodon.jsx deleted file mode 100644 index 3f58b257a..000000000 --- a/app/assets/javascripts/components/containers/mastodon.jsx +++ /dev/null @@ -1,320 +0,0 @@ -import { Provider } from 'react-redux'; -import PropTypes from 'prop-types'; -import configureStore from '../store/configureStore'; -import { - refreshTimelineSuccess, - updateTimeline, - deleteFromTimelines, - refreshTimeline, - connectTimeline, - disconnectTimeline -} from '../actions/timelines'; -import { showOnboardingOnce } from '../actions/onboarding'; -import { updateNotifications, refreshNotifications } from '../actions/notifications'; -import createBrowserHistory from 'history/lib/createBrowserHistory'; -import { - applyRouterMiddleware, - useRouterHistory, - Router, - Route, - IndexRedirect, - IndexRoute -} from 'react-router'; -import { useScroll } from 'react-router-scroll'; -import UI from '../features/ui'; -import Status from '../features/status'; -import GettingStarted from '../features/getting_started'; -import PublicTimeline from '../features/public_timeline'; -import CommunityTimeline from '../features/community_timeline'; -import AccountTimeline from '../features/account_timeline'; -import HomeTimeline from '../features/home_timeline'; -import Compose from '../features/compose'; -import Followers from '../features/followers'; -import Following from '../features/following'; -import Reblogs from '../features/reblogs'; -import Favourites from '../features/favourites'; -import HashtagTimeline from '../features/hashtag_timeline'; -import Notifications from '../features/notifications'; -import FollowRequests from '../features/follow_requests'; -import GenericNotFound from '../features/generic_not_found'; -import FavouritedStatuses from '../features/favourited_statuses'; -import Blocks from '../features/blocks'; -import Mutes from '../features/mutes'; -import Report from '../features/report'; -import { IntlProvider, addLocaleData } from 'react-intl'; -import ar from 'react-intl/locale-data/ar'; -import en from 'react-intl/locale-data/en'; -import de from 'react-intl/locale-data/de'; -import eo from 'react-intl/locale-data/eo'; -import es from 'react-intl/locale-data/es'; -import fa from 'react-intl/locale-data/fa'; -import fi from 'react-intl/locale-data/fi'; -import fr from 'react-intl/locale-data/fr'; -import he from 'react-intl/locale-data/he'; -import hu from 'react-intl/locale-data/hu'; -import it from 'react-intl/locale-data/it'; -import ja from 'react-intl/locale-data/ja'; -import pt from 'react-intl/locale-data/pt'; -import nl from 'react-intl/locale-data/nl'; -import no from 'react-intl/locale-data/no'; -import ru from 'react-intl/locale-data/ru'; -import uk from 'react-intl/locale-data/uk'; -import zh from 'react-intl/locale-data/zh'; -import bg from 'react-intl/locale-data/bg'; -import id from 'react-intl/locale-data/id'; -import { localeData as zh_hk } from '../locales/zh-hk'; -import { localeData as zh_cn } from '../locales/zh-cn'; -import pt_br from '../locales/pt-br'; -import getMessagesForLocale from '../locales'; -import { hydrateStore } from '../actions/store'; -import createStream from '../stream'; - -const store = configureStore(); -const initialState = JSON.parse(document.getElementById("initial-state").textContent); -store.dispatch(hydrateStore(initialState)); - -const browserHistory = useRouterHistory(createBrowserHistory)({ - basename: '/web' -}); - -addLocaleData([ - ...en, - ...ar, - ...de, - ...eo, - ...es, - ...fa, - ...fi, - ...fr, - ...he, - ...hu, - ...it, - ...ja, - ...pt, - ...pt_br, - ...nl, - ...no, - ...ru, - ...uk, - ...zh, - ...zh_hk, - ...zh_cn, - ...bg, - ...id, -]); - -const getTopWhenReplacing = (previous, { location }) => location && location.action === 'REPLACE' && [0, 0]; - -const hiddenColumnContainerStyle = { - position: 'absolute', - left: '0', - top: '0', - visibility: 'hidden' -}; - -class Container extends React.PureComponent { - - constructor(props) { - super(props); - - this.state = { - renderedPersistents: [], - unrenderedPersistents: [], - }; - } - - componentWillMount () { - this.unlistenHistory = null; - - this.setState(() => { - return { - mountImpersistent: false, - renderedPersistents: [], - unrenderedPersistents: [ - {pathname: '/timelines/home', component: HomeTimeline}, - {pathname: '/timelines/public', component: PublicTimeline}, - {pathname: '/timelines/public/local', component: CommunityTimeline}, - - {pathname: '/notifications', component: Notifications}, - {pathname: '/favourites', component: FavouritedStatuses} - ], - }; - }, () => { - if (this.unlistenHistory) { - return; - } - - this.unlistenHistory = browserHistory.listen(location => { - const pathname = location.pathname.replace(/\/$/, '').toLowerCase(); - - this.setState(oldState => { - let persistentMatched = false; - - const newState = { - renderedPersistents: oldState.renderedPersistents.map(persistent => { - const givenMatched = persistent.pathname === pathname; - - if (givenMatched) { - persistentMatched = true; - } - - return { - hidden: !givenMatched, - pathname: persistent.pathname, - component: persistent.component - }; - }), - }; - - if (!persistentMatched) { - newState.unrenderedPersistents = []; - - oldState.unrenderedPersistents.forEach(persistent => { - if (persistent.pathname === pathname) { - persistentMatched = true; - - newState.renderedPersistents.push({ - hidden: false, - pathname: persistent.pathname, - component: persistent.component - }); - } else { - newState.unrenderedPersistents.push(persistent); - } - }); - } - - newState.mountImpersistent = !persistentMatched; - - return newState; - }); - }); - }); - } - - componentWillUnmount () { - if (this.unlistenHistory) { - this.unlistenHistory(); - } - - this.unlistenHistory = "done"; - } - - render () { - // Hide some components rather than unmounting them to allow to show again - // quickly and keep the view state such as the scrolled offset. - const persistentsView = this.state.renderedPersistents.map((persistent) => -
- -
- ); - - return ( - - {this.state.mountImpersistent && this.props.children} - {persistentsView} - - ); - } -} - -Container.propTypes = { - children: PropTypes.node, -}; - -class Mastodon extends React.Component { - - componentDidMount() { - const { locale } = this.props; - const streamingAPIBaseURL = store.getState().getIn(['meta', 'streaming_api_base_url']); - const accessToken = store.getState().getIn(['meta', 'access_token']); - - this.subscription = createStream(streamingAPIBaseURL, accessToken, 'user', { - - connected () { - store.dispatch(connectTimeline('home')); - }, - - disconnected () { - store.dispatch(disconnectTimeline('home')); - }, - - received (data) { - switch(data.event) { - case 'update': - store.dispatch(updateTimeline('home', JSON.parse(data.payload))); - break; - case 'delete': - store.dispatch(deleteFromTimelines(data.payload)); - break; - case 'notification': - store.dispatch(updateNotifications(JSON.parse(data.payload), getMessagesForLocale(locale), locale)); - break; - } - }, - - reconnected () { - store.dispatch(connectTimeline('home')); - store.dispatch(refreshTimeline('home')); - store.dispatch(refreshNotifications()); - } - - }); - - // Desktop notifications - if (typeof window.Notification !== 'undefined' && Notification.permission === 'default') { - Notification.requestPermission(); - } - - store.dispatch(showOnboardingOnce()); - } - - componentWillUnmount () { - if (typeof this.subscription !== 'undefined') { - this.subscription.close(); - this.subscription = null; - } - } - - render () { - const { locale } = this.props; - - return ( - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ); - } - -} - -Mastodon.propTypes = { - locale: PropTypes.string.isRequired -}; - -export default Mastodon; diff --git a/app/assets/javascripts/components/containers/status_container.jsx b/app/assets/javascripts/components/containers/status_container.jsx deleted file mode 100644 index ae83d36c9..000000000 --- a/app/assets/javascripts/components/containers/status_container.jsx +++ /dev/null @@ -1,117 +0,0 @@ -import { connect } from 'react-redux'; -import Status from '../components/status'; -import { makeGetStatus } from '../selectors'; -import { - replyCompose, - mentionCompose -} from '../actions/compose'; -import { - reblog, - favourite, - unreblog, - unfavourite -} from '../actions/interactions'; -import { - blockAccount, - muteAccount -} from '../actions/accounts'; -import { deleteStatus } from '../actions/statuses'; -import { initReport } from '../actions/reports'; -import { openModal } from '../actions/modal'; -import { createSelector } from 'reselect' -import { isMobile } from '../is_mobile' -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; - -const messages = defineMessages({ - deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' }, - deleteMessage: { id: 'confirmations.delete.message', defaultMessage: 'Are you sure you want to delete this status?' }, - blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' }, - muteConfirm: { id: 'confirmations.mute.confirm', defaultMessage: 'Mute' }, -}); - -const makeMapStateToProps = () => { - const getStatus = makeGetStatus(); - - const mapStateToProps = (state, props) => ({ - status: getStatus(state, props.id), - me: state.getIn(['meta', 'me']), - boostModal: state.getIn(['meta', 'boost_modal']), - autoPlayGif: state.getIn(['meta', 'auto_play_gif']) - }); - - return mapStateToProps; -}; - -const mapDispatchToProps = (dispatch, { intl }) => ({ - - onReply (status, router) { - dispatch(replyCompose(status, router)); - }, - - onModalReblog (status) { - dispatch(reblog(status)); - }, - - onReblog (status, e) { - if (status.get('reblogged')) { - dispatch(unreblog(status)); - } else { - if (e.shiftKey || !this.boostModal) { - this.onModalReblog(status); - } else { - dispatch(openModal('BOOST', { status, onReblog: this.onModalReblog })); - } - } - }, - - onFavourite (status) { - if (status.get('favourited')) { - dispatch(unfavourite(status)); - } else { - dispatch(favourite(status)); - } - }, - - onDelete (status) { - dispatch(openModal('CONFIRM', { - message: intl.formatMessage(messages.deleteMessage), - confirm: intl.formatMessage(messages.deleteConfirm), - onConfirm: () => dispatch(deleteStatus(status.get('id'))) - })); - }, - - onMention (account, router) { - dispatch(mentionCompose(account, router)); - }, - - onOpenMedia (media, index) { - dispatch(openModal('MEDIA', { media, index })); - }, - - onOpenVideo (media, time) { - dispatch(openModal('VIDEO', { media, time })); - }, - - onBlock (account) { - dispatch(openModal('CONFIRM', { - message: @{account.get('acct')} }} />, - confirm: intl.formatMessage(messages.blockConfirm), - onConfirm: () => dispatch(blockAccount(account.get('id'))) - })); - }, - - onReport (status) { - dispatch(initReport(status.get('account'), status)); - }, - - onMute (account) { - dispatch(openModal('CONFIRM', { - message: @{account.get('acct')} }} />, - confirm: intl.formatMessage(messages.muteConfirm), - onConfirm: () => dispatch(muteAccount(account.get('id'))) - })); - }, - -}); - -export default injectIntl(connect(makeMapStateToProps, mapDispatchToProps)(Status)); -- cgit