For example a Lisp system may consist of starting a memory image from disk, which leads to a live running memory heap. The tree shaker then may break unused links in memory - either automatic or under programmer direction. The garbage collector then frees the unused memory. Lisp then dumps a new (typically smaller) image, which has unused code and data removed.
Such features appeared no later than end 1980s.
That's exactly how all dead code elimination works. How else would you do it?
Tree shaking happens at the import level. If I say `import { abc } from 'some-lib'`, tree shaking won’t include any other objects some-lib may export.
Removing a branch that can never be true, like `if ('production' === 'production') { … } else { /* dead code */ }` is dead code elimination, but webpack wouldn’t consider that tree shaking.