Ведущий Front-end Ultimate Guitar.
Не пью, не курю, не ругаюсь матом (грязно)
Когда интернет широкий, то и проблем нет
| Метрика | Старое | Новое |
|---|---|---|
| Вес | 84кб + 50кб (реклама) | 158кб |
| Dom ready 3G | 3.8c | 5.0c |
| PageSpeed | 99 | 84 |
Продажи — -50%
| Метрика | Старое | Новое |
|---|---|---|
| Вес | 70кб + 50кб (реклама) | 144кб |
| Dom ready 3G | 2.5c | 3.4c |
| PageSpeed | 99 | 89 |
Продажи — -10%
| Метрика | Старое | Новое |
|---|---|---|
| Вес | 70кб + 50кб (реклама) | 112кб |
| Dom ready 3G | 2.5c | 2.9c |
| PageSpeed | 99 | 93 |
Продажи — +2%
"Все должно быть измерено"
"Хорошая сиcтема - эта та, которая позволяет избежать ошибок"
const routingMap = {
tab: {
textTab: {
index: PAGE_TYPE_TAB_TEXT,
},
},
common: {
system: {
error: {
[ROUTE_TYPE_DEFAULT]: PAGE_TYPE_ERROR,
}
}
}
}
const getRouteType = ({ routingMap, props }) => {
return routingMap?[props.module]?[props.controller]?[props.action] || ROUTE_TYPE_DEFAULT;
}
const textTabLoader = () => [
import(/* webpackChunkName: 'tab_text' */ './TextTabContentContainer'),
import(/* webpackChunkName: 'tab_text' */ '../dataConverter/tabDataConverterDesktop'),
]
const loadersMap = {
[PAGE_TYPE_ERROR]: getErrorContainer,
[PAGE_TYPE_TAB_TEXT]: textTabLoader,
}
class PageContainer extends Component {
Content = null
update = chunks => {
const [ Content, convert ] = chunks.map(chunk => chunk.default);
this.Content = Content;
this.props.convertPageData({
payload: this.props.data,
convert,
});
}
loadPage() {
const routeType = getRouteType({
props: this.props.routeProps,
routingMap: this.props.routungMap,
});
this.props.loadersMap[routeType]().then(this.update);
}
render() {
return (
<LayoutContainer>{this.Content}</LayoutContainer>
)
}
}
class PageContainer extends Component {
Content = null
update = chunks => {
const [ Content, convert ] = chunks.map(chunk => chunk.default);
this.Content = Content;
this.props.convertPageData({
payload: this.props.data,
convert,
});
}
loadPage() {
const routeType = getRouteType({
props: this.props.routeProps,
routingMap: this.props.routungMap,
});
this.props.loadersMap[routeType]().then(this.update);
}
render() {
return (
<LayoutContainer>{this.Content}</LayoutContainer>
)
}
}
class PageContainer extends Component {
Content = null
update = chunks => {
const [ Content, convert ] = chunks.map(chunk => chunk.default);
this.Content = Content;
this.props.convertPageData({
payload: this.props.data,
convert,
});
}
loadPage() {
const routeType = getRouteType({
props: this.props.routeProps,
routingMap: this.props.routungMap,
});
this.props.loadersMap[routeType]().then(this.update);
}
render() {
return (
<LayoutContainer>{this.Content}</LayoutContainer>
)
}
}
class PageContainer extends Component {
Content = null
update = chunks => {
const [ Content, convert ] = chunks.map(chunk => chunk.default)
this.Content = Content;
this.props.convertPageData({
payload: this.props.data,
convert,
});
}
loadPage() {
const routeType = getRouteType({
props: this.props.routeProps,
routingMap: this.props.routungMap,
});
this.props.loadersMap[routeType]().then(this.update);
}
render() {
return (
<LayoutContainer>{this.Content}</LayoutContainer>
)
}
}
class PageContainer extends Component {
Content = null
update = chunks => {
const [ Content, convert ] = chunks.map(chunk => chunk.default);
this.Content = Content;
this.props.convertPageData({
payload: this.props.data,
convert,
});
}
loadPage() {
const routeType = getRouteType({
props: this.props.routeProps,
routingMap: this.props.routungMap,
});
this.props.loadersMap[routeType]().then(this.update);
}
render() {
return (
<LayoutContainer>{this.Content}</LayoutContainer>
)
}
}
import { compose, applyMiddleware, combineReducers } from 'redux'
const createStore = ({ initialState, reducers }) => {
const middlewares = applyMiddleware(thunk);
const createStore = compose(middlewares)(createStore);
const store = createStore(combineReducers(reducers), initialState);
store.reducers = reducers;
store.asyncReducers = {};
return store
}
const injectAsyncReducer = ({ store, name, asyncReducer }) => {
store.asyncReducers[name] = asyncReducer;
store.replaceReducer(combineReducers({
...store.reducers,
...store.asyncReducers,
}));
}
const injectAsyncReducer = ({ store, name, asyncReducer }) => {
store.asyncReducers[name] = asyncReducer;
store.replaceReducer(combineReducers({
...store.reducers,
...store.asyncReducers,
}));
}
class PageContainer {
update = chunks => {
const [ Content, convert, asyncReducer ] = chunks.map(chunk.default);
injectAsyncReducer({
store: this.context.store,
name: STORE_REDUCER_NAME_CONTENT,
asyncReducer,
});
//...
}
}
// @ug/helpers/redux.js
const getLoadableAction =
getLoader =>
({ name, async }) =>
(...args) => (dispatch, getState) =>
getLoader().then(({ [name]: action }) => {
const result = action(...args)
async ? result(dispatch, getState) : dispatch(result)
})
}
// @ug/helpers/redux.js
const getLoadableAction =
getLoader =>
({ name, async }) =>
(...args) => (dispatch, getState) =>
getLoader().then(({ [name]: action }) => {
const result = action(...args)
async ? result(dispatch, getState) : dispatch(result)
})
}
// @ug/helpers/redux.js
const getLoadableAction =
getLoader =>
({ name, async }) =>
(...args) => (dispatch, getState) =>
getLoader().then(({ [name]: action }) => {
const result = action(...args)
async ? result(dispatch, getState) : dispatch(result)
})
}
// @ug/helpers/redux.js
const getLoadableAction =
getLoader =>
({ name, async }) =>
(...args) => (dispatch, getState) =>
getLoader().then(({ [name]: action }) => {
const result = action(...args)
async ? result(dispatch, getState) : dispatch(result)
})
}
import { getLoadableAction } from '@ug/helpers/redux';
const getCommentsAction = getLoadableAction(() => import('./commentsActions'));
export const addComment = getCommentsAction({ name: 'addComment', async: true });
export const editComment = getCommentsAction({ name: 'editComment', async: true });
//...
const MyComponent = ({ url, title }) => ( <ResponsiveImage url={url} size={40} alt={title} /> )
import Loadable from 'react-loadable'; import logHelper from './logHelper'; const createLoadable => Loadable({ loader, loading(props) { if (props.error) { logHelper.error(props.error) } return null }, }); const AsyncFooterContainer = createLoadable(() => import('./FooterContainer'));
import Loadable from 'react-loadable'; import logHelper from './logHelper'; const createLoadable => Loadable({ loader, loading(props) { if (props.error) { logHelper.error(props.error) } return null }, }); const AsyncFooterContainer = createLoadable(() => import('./FooterContainer'));
Preact https://preactjs.com/
module.exports = {
resolve: {
alias: {
react: 'preact-compat',
'react-dom': 'preact-compat',
// ...
},
}
}
const createCssLoader = ({ isDevelopment, cssLoader }) => ({
loader: 'css-loader',
options: {
minimize: !isDevelopment,
sourceMap: false, // isDevelopment,
modules: true,
camelCase: true,
url: true,
importLoaders: 1,
localIdentName: isDevelopment ? '[name]--[local]--[hash:base64:5]' : '[hash:base64:5]',
...(cssLoader || {}),
},
});
const getSymbolContent = async filePath => { const content = await readFileAsync(filePath); return unwrap(content); }
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); r return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; } var getSymbolContent = function () { var _ref = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee(filePath) { var content; return regeneratorRuntime.wrap(function _callee$(_context) { while (1) { switch (_context.prev = _context.next) { case 0: _context.next = 2; return readFileAsync(filePath); case 2: content = unwrap(_context.sent); return _context.abrupt("return"); case 4: case "end": return _context.stop(); } } }, _callee, undefined); })); return function getSymbolContent(_x) { return _ref.apply(this, arguments); }; }();
const getSymbolContent = filePath => readFileAsync(filePath).then(unwrap)
const getSymbolContent = function(filePath) { return readFileAsync(filePath).then(unwrap); }
var r=function(){var r=a(m.mark(function r(e){var n;return m.wrap(function(r){for(;;)switch(r.prev=r.next){ case 0:return r.next=2,y(x);case 2:return n=r.sent ,r.abrupt("return",u(n));case 4:case"end":return r.stop()}}, r,void 0)}));return function(e){return r.apply(this,arguments)}}();
var m=function(n){return b(x).then(e)};
@connect(state => ({ isOpen: state.notifications.isOpen, })) class NotificationMobilePageContainer extends Component { render() { return this.props.isOpen && <AsyncUserNotificationsContainer /> } }
function e() { return function(n, t) { if (!(n instanceof t)) throw new TypeError("Cannot call a class as a function") }(this, e), function(n, t) { if (!n) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return !t || "object" != typeof t && "function" != typeof t ? n : t }(this, t.apply(this, arguments)) } return function(n, t) { if ("function" != typeof t && null !== t) throw new TypeError("Super expression must either be null or a function, not " + typeof t); n.prototype = Object.create(t && t.prototype, { constructor: { value: n, enumerable: !1, writable: !0, configurable: !0 } }), t && (Object.setPrototypeOf ? Object.setPrototypeOf(n, t) : n.__proto__ = t) }(e, t),
var NotificationMobilePageContainer = (function(_Component) {
_inherits(NotificationMobilePageContainer, _Component);
function NotificationMobilePageContainer() {
_classCallCheck(this, NotificationMobilePageContainer);
return _possibleConstructorReturn(this, _Component.apply(this, arguments));
}
NotificationMobilePageContainer.prototype.render = function render() {
return (
this.props.isOpen &&
React.createElement(AsyncUserNotificationsContainer, null)
);
};
return NotificationMobilePageContainer;
})(Component);
connect(function(state) {
return {
isOpen: state.notifications.isOpen
};
})(NotificationMobilePageContainer);
compose(
connect(state => ({
isOpen: state.notifications.isOpen,
})),
branch(props => props.isOpen, renderNothing)
)(NotificationMobilePageContainer)