No tree shaking after dead code removal in dynamic import
Bug report
With mode: production on, and "sideEffects:false", exported function that are unused after dead code removal remain in the bundle, if the module is imported dynamically. https://stackblitz.com/edit/github-2yf5yf?file=dist/main.js
What is the current behavior? unused function not get removed if the file is imported dynamically
If the current behavior is a bug, please provide the steps to reproduce.
- entry: index.ts
import { treeShakingTestSync } from './treeshaking-test';
const foo = treeShakingTestSync();
console.log(foo);
- treeshaking-test.ts
import { b } from "./await-import-modules";
export const treeShakingTestAsync = async () => {
console.log('treeShakingTestAsync');
const { b } = await import('./await-import-modules');
return b;
};
export const treeShakingTestSync = () => {
console.log('treeShakingTestSync');
return b;
};
- await-import-modules.ts.ts
export function a() { console.log('FuncA') };
export function b() { console.log('FuncB') };
- webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.ts',
mode: 'production',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist'),
},
};
- package.json
{
"name": "getting-started-using-a-configuration",
"version": "1.0.0",
"private": true,
"scripts": {
"build": "webpack",
"start": "serve dist"
},
"sideEffects": false,
"keywords": [],
"author": "",
"license": "MIT",
"devDependencies": {
"serve": "^12.0.0",
"ts-loader": "^9.3.1",
"typescript": "^4.8.3",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.2"
}
}
What is the expected behavior? "treeShakingTestAsync" cannot be found in the output file, as expected. But 'FuncA' can be found, not get tree-shaken or deadcode removed. 'FuncA' should be tree-shaken
Other relevant information: webpack version: 5.74.0 Node.js version: v14.15.0 Operating System: macOS 12.0.1 Additional tools:
I found some relates issue #13028, and understand this could not be done right now. This issue can be closed in favor of #13028 #14800
But still got some related questions @vankop @alexander-akait :
- As mentioned in #13028, magic comment is hard to maintain, especially in large project. If dynamic import is the reason, can we add some intermediate files to avoid this problem?
I fiddle around a little bit , by adding an
intermediate.tsto statically import from module that dynamic import originally. intermediate.ts. its basically the same as magic comment, expect it can be refactor (still a undesired workaround, until #14800 get resolved).
export { b } from "./await-import-modules";
treeshaking-test.ts
import { b } from "./intermediate";
export const treeShakingTestAsync = async () => {
console.log('treeShakingTestAsync');
const { b } = await import('./intermediate');
return b;
};
in this way, unused function 'FuncA' cant't be found in the output file, as expected. is it recommended way to solve this problem? 2. Could you elaborate on the details why #14800 is hard to implement? 3. If production mode is on , and minify set false, why unused export file is still in the output? shouldn't it be tree shaken first instead of code removal?
@icy0307 This is not hard, the main problem is babel and another transpilers and renaming variables, yes it's fixable, but need more work, if you want to help us feel free to continue dicussion here https://github.com/webpack/webpack/issues/14800 and ask questions
There is a PR with attempts to resolve, so you can build own solution
let's close this, because the root of the problem is https://github.com/webpack/webpack/issues/14800