Tree shaking (встряхивание дерева) — термин объединения модулей JavaScript, обозначающий статический анализ всего импортированного кода и исключение того, что на самом деле не используется.
Для более прямолинейной аналогии рассмотрим живое дерево. Дерево встряхивается, и это заставляет мертвые листья отваливаться, оставляя только живые. В основе tree shaking лежит концепция живого включения кода (live code inclusion): мы включаем части, необходимые для начала, в отличие от удаления ненужных частей в конце — устранения «мертвого кода» (dead code elimination).
Tree shaking зависит от import и export модулей ES2015. Выражения import и export составляют статическую структуру модуля приложения. Когда модули объединяются для развертывания приложения, tree shaker анализирует статическую структуру модуля, чтобы исключить неиспользуемый экспорт, уменьшив размер окончательного пакета.
ES2015 позволяет указывать явный импорт. Например, вместо импорта всей библиотеки RxJS мы можем импортировать именно то, что хотим:
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
Это отличается от динамического выражения require, используемого CommonJS или AMD. Tree shaking использует этот принцип для перемещения по зависимостям и исключения ненужных зависимостей для уменьшения размера приложения.
Принцип tree shaking не нов, но он только недавно был популяризирован с помощью сборщика rollup.js, объединяющего модули приложения. Webpack 2 также использует tree shaking. Концепция tree shaking также распространена в Angular с компиляцией AOT.
class ArrowUp extends Component {
state = {
isVisible: false,
};
componentDidMount() {
window.addEventListener('scroll', this.handleScroll);
}
componentWillUnmount() {
window.removeEventListener('scroll', this.handleScroll);
}
handleScroll = () => {
if (window.scrollY >= SOME_VALUE && !this.state.isVisible) {
this.setState({ isVisible: true });
} else if (window.scrollY < SOME_VALUE && this.state.isVisible) {
this.setState({ isVisible: false });
}
};
render() { /* ... */ }
}
element.scrollIntoView();
handleLinkClick = e => {
e.preventDefault();
const element = document.getElementById(e.target.href);
element.scrollIntoView();
};
class Child extends Component {
render() {
const { handleChange } = this.props;
return (
<Wrapper>
<SomeInput onChange={handleChange} />
</Wrapper>
);
}
}
handleChange = e => {
const { name, value } = this.props;
this.setState({ [name]: value }, this.calculate);
};
/common
/api
/components
/ducks
/entities
/sagas
/selectors
/utils
/features
/Feature1
/Feature2
/Feature3
/Feature4
...
/FeatureN
/Main
/pages
index.js
App.js
routes.js
rootReducer.js
rootSaga.js
store.js
/Auth
/pages
index.js
App.js
routes.js
rootReducer.js
rootSaga.js
store.js
...
/features
/Accounts
/components
index.js
accountsDucks.js
accountsSaga.js
accountsSelectors.js
accountsApi.js
Accounts.js
AccountsContainer.js
/actions
/common
/components
/core
/Feed
/Profile
...
/constraints
/containers
/entries
/locales
/pages
/reducers
/utils
...
app.use((req, res, next) => {
console.log('Time: ', Date.now());
next();
});
app.use(express.static(__dirname + '/public'));
app.get("/about", (req, res) => { /* */}); // ( 1 )
app.get("/home", (req, res) => { /* */}); // ( 2 )
app.get("*", (req, res) => { /* */}); // ( 3 )
app.get("/never", (req, res) => { /* */}); // ( 4 )
GET https://site/public/img/1.png
GET https://site/home
GET https://site/feed
GET https://site/never
Time: <текущее время>
container.innerHTML += "<br />";
var br = document.createElement('br');
container.appendChild(br);
- Каждый раз нужно импортировать текст-контент и брать значение по нужным ключам
i18nMessage('landing_header');
i18nPlural('comments_count', comments.size);
i18nWrapper('landing_caption', [<strong />]);