I'm trying to create a tree shakable library with webpack but it's not working. No matter what I do, when I consume the library in a separate project, the entire library is included in the output.
Library
Here are the relevant files for the library.
src/sdk/index.ts
export const addOne = function(x: number): number {
return x + 1;
}
export const addTwo = function(x: number): number {
return x + 2;
}
export const addThree = function(x: number): number {
return x + 3;
}
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"module": "es6",
"declaration": false,
"sourceMap": false,
"outDir": "./dist/",
"strict": true,
"moduleResolution": "node",
"allowJs": true,
"strictPropertyInitialization": false,
"lib": [
"es2015",
"dom"
],
"typeRoots": [
"src/customTypes",
"node_modules/@types"
]
}
}
package.json
{
"name": "test",
"version": "0.3.0",
"description": "",
"scripts": {
"build": "webpack --config webpack.prod.js",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"clean-webpack-plugin": "^3.0.0",
"ts-loader": "^8.0.14",
"typescript": "^4.1.3",
"webpack": "^5.14.0",
"webpack-cli": "^4.3.1"
},
"sideEffects": false
}
webpack.prod.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports ={
mode: 'production',
entry: {
'test': './src/sdk/index.ts',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd',
library: 'test',
umdNamedDefine: true,
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'ts-loader',
exclude: /node_modules/,
},
],
},
plugins: [
new CleanWebpackPlugin(),
],
};
Sample
And here are the files for the sample that consumes the library. The output of the above library is placed in the src folder, next to sample.js
sample.js
import { addOne } from './test';
console.log('HELLO')
console.log(addOne(1));
webpack.prod.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
module.exports = {
mode: 'production',
entry: {
'sample': './src/sample.js',
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist'),
libraryTarget: 'umd',
library: 'sample',
umdNamedDefine: true,
},
plugins: [
new CleanWebpackPlugin(),
new CopyPlugin({
patterns: [
{ from: 'src/index.html', to: path.resolve(__dirname, 'dist') },
]
})
],
};
When I open the output of the sample, I can see that all the functions from the library are there. It should only have addOne since that's the only one I'm importing.
If instead of using the library in the sample, I create a file with the same content as the lib:
export const addOne = function(x){
return x + 1;
}
export const addTwo = function(x){
return x + 2;
}
export const addThree = function(x){
return x + 3;
}
Then tree shaking is working properly. addTwo and AddThree are not there.
So I think the issue is how I'm generating the library and the fact that I have libraryTarget set to umd, but I don't see any options to specify esm. Or maybe it is something else.
Turns out Webpack cannot do this yet: https://github.com/webpack/webpack/issues/2933. Hopefully, this will be available in the next major release. I'll use Rollup for now.