无法在 Webpack、TypeScript 项目中摇晃 lodash
Not able to tree shake lodash in a Webpack, TypeScript project
我的目标是 webpack.prod.js
中的 tree shake lodash
(以及其他)。这是我的配置文件。为了完整起见,我还将包括 webpack.dev.js
、webpack.common.js
、tsconfig.json
和 package.json
:
webpack.common.js
:
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.(png|svg|jpg|gif|obj)$/,
use: [
'file-loader'
]
},
{
test: /\.glsl$/,
loader: 'webpack-glsl-loader'
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.ts$/,
enforce: 'pre',
loader: 'tslint-loader',
options: { failOnHint: true }
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
entry: {
app: './src/index.ts'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Production'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
webpack.dev.js
:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const JarvisPlugin = require("webpack-jarvis");
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
module: {
rules: [
{
test: /\.(png|svg|jpg|gif|obj)$/,
use: [
'file-loader'
]
},
{
test: /\.glsl$/,
loader: 'webpack-glsl-loader'
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.ts$/,
enforce: 'pre',
loader: 'tslint-loader',
options: { failOnHint: true }
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
entry: {
app: './src/index.ts'
},
devtool: 'inline-source-map',
devServer: {
contentBase: './dist'
},
plugins: [
new HtmlWebpackPlugin({ title: 'urknall-core dev' }),
new BundleAnalyzerPlugin({ analyzerPort: 8888 }),
new JarvisPlugin({ port: 1337 }),
],
output: {
filename: '[name].bundle.js',
publicPath: '/'
}
};
webpack.prod.js
:
const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
devtool: 'source-map',
plugins: [
new UglifyJSPlugin({
sourceMap: true,
test: /\.js($|\?)/i,
uglifyOptions: {
compress: true
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
]
});
tsconfig.json
:
{
"compilerOptions": {
"outDir": "./dist/",
"declaration": true,
"declarationDir": "./types",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es6",
}
}
package.json
:
{
"name": "bla",
"version": "0.0.1",
"description": "",
"main": "index.ts",
"types": "./dist/types/",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.prod.js",
"start": "webpack-dev-server --open --config webpack.dev.js",
"watch": "webpack --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/gl-matrix": "^2.4.0",
"@types/lodash": "^4.14.104",
"@types/node": "^8.9.4",
"@types/webgl2": "^0.0.2",
"@types/webpack-dev-middleware": "^1.12.3",
"clean-webpack-plugin": "^0.1.18",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.30.1",
"image-webpack-loader": "^3.6.0",
"style-loader": "^0.18.2",
"ts-loader": "^2.3.7",
"ts-node": "^3.3.0",
"tslint": "^5.9.1",
"tslint-loader": "^3.5.3",
"typescript": "^2.7.1",
"uglifyjs-webpack-plugin": "^1.2.2",
"webpack": "^3.11.0",
"webpack-bundle-analyzer": "^2.11.0",
"webpack-dev-middleware": "^1.12.0",
"webpack-dev-server": "^2.11.2",
"webpack-glsl-loader": "^1.0.1",
"webpack-jarvis": "^0.3.0",
"webpack-merge": "^4.1.2"
},
"dependencies": {
"gl-matrix": "^2.4.0",
"lodash-es": "^4.17.5"
}
}
使用此配置,app.bundle.js
生成 507 KB 的文件,而 app.bundle.js.map
为 1.6 MB。如果我不丑化构建输出,我可以看到整个 lodash 库都被写入了文件。我还看到了一些其他功能,例如 gl-matrix
被写入文件,尽管我什至没有使用它们。
我也在开发中 运行 webpack-bundle-analyzer
并且输出与生产没有区别。由于缩小,只有 budle 文件是 ~1.4 MB 而不是 1.6 MB。
我在整个项目中只加载lodash
两次,比如:
import { some, find, cloneDeep } from 'lodash';
不再使用 lodash
函数。为什么 Webpack
会使我的 app.bundle.js
膨胀?
我的配置有问题吗?
鉴于标准 lodash
包的现有导出样式,您有两种选择来解决此问题:
- 移动到一个 lodash 包,它以一种可以直接插入导入模式的方式使用导出。正如@alex-rokabilis 在评论中提到的,一个可用的包是 lodash-es
更新您的导入以使用标准 lodash
包使用的导出。如果您查看 lodash's npm page,您会发现它们支持从路径中挑选特定方法。
import some from 'lodash/fp/some';
import find from 'lodash/fp/find';
import cloneDeep from 'lodash/fp/cloneDeep';
我的目标是 webpack.prod.js
中的 tree shake lodash
(以及其他)。这是我的配置文件。为了完整起见,我还将包括 webpack.dev.js
、webpack.common.js
、tsconfig.json
和 package.json
:
webpack.common.js
:
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.(png|svg|jpg|gif|obj)$/,
use: [
'file-loader'
]
},
{
test: /\.glsl$/,
loader: 'webpack-glsl-loader'
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.ts$/,
enforce: 'pre',
loader: 'tslint-loader',
options: { failOnHint: true }
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
entry: {
app: './src/index.ts'
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Production'
})
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
webpack.dev.js
:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const JarvisPlugin = require("webpack-jarvis");
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
module: {
rules: [
{
test: /\.(png|svg|jpg|gif|obj)$/,
use: [
'file-loader'
]
},
{
test: /\.glsl$/,
loader: 'webpack-glsl-loader'
},
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
},
{
test: /\.ts$/,
enforce: 'pre',
loader: 'tslint-loader',
options: { failOnHint: true }
}
]
},
resolve: {
extensions: [".tsx", ".ts", ".js"]
},
entry: {
app: './src/index.ts'
},
devtool: 'inline-source-map',
devServer: {
contentBase: './dist'
},
plugins: [
new HtmlWebpackPlugin({ title: 'urknall-core dev' }),
new BundleAnalyzerPlugin({ analyzerPort: 8888 }),
new JarvisPlugin({ port: 1337 }),
],
output: {
filename: '[name].bundle.js',
publicPath: '/'
}
};
webpack.prod.js
:
const webpack = require('webpack');
const merge = require('webpack-merge');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
const common = require('./webpack.common.js');
module.exports = merge(common, {
devtool: 'source-map',
plugins: [
new UglifyJSPlugin({
sourceMap: true,
test: /\.js($|\?)/i,
uglifyOptions: {
compress: true
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production')
}),
]
});
tsconfig.json
:
{
"compilerOptions": {
"outDir": "./dist/",
"declaration": true,
"declarationDir": "./types",
"sourceMap": true,
"noImplicitAny": true,
"module": "commonjs",
"target": "es6",
}
}
package.json
:
{
"name": "bla",
"version": "0.0.1",
"description": "",
"main": "index.ts",
"types": "./dist/types/",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack --config webpack.prod.js",
"start": "webpack-dev-server --open --config webpack.dev.js",
"watch": "webpack --watch"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/gl-matrix": "^2.4.0",
"@types/lodash": "^4.14.104",
"@types/node": "^8.9.4",
"@types/webgl2": "^0.0.2",
"@types/webpack-dev-middleware": "^1.12.3",
"clean-webpack-plugin": "^0.1.18",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.30.1",
"image-webpack-loader": "^3.6.0",
"style-loader": "^0.18.2",
"ts-loader": "^2.3.7",
"ts-node": "^3.3.0",
"tslint": "^5.9.1",
"tslint-loader": "^3.5.3",
"typescript": "^2.7.1",
"uglifyjs-webpack-plugin": "^1.2.2",
"webpack": "^3.11.0",
"webpack-bundle-analyzer": "^2.11.0",
"webpack-dev-middleware": "^1.12.0",
"webpack-dev-server": "^2.11.2",
"webpack-glsl-loader": "^1.0.1",
"webpack-jarvis": "^0.3.0",
"webpack-merge": "^4.1.2"
},
"dependencies": {
"gl-matrix": "^2.4.0",
"lodash-es": "^4.17.5"
}
}
使用此配置,app.bundle.js
生成 507 KB 的文件,而 app.bundle.js.map
为 1.6 MB。如果我不丑化构建输出,我可以看到整个 lodash 库都被写入了文件。我还看到了一些其他功能,例如 gl-matrix
被写入文件,尽管我什至没有使用它们。
我也在开发中 运行 webpack-bundle-analyzer
并且输出与生产没有区别。由于缩小,只有 budle 文件是 ~1.4 MB 而不是 1.6 MB。
我在整个项目中只加载lodash
两次,比如:
import { some, find, cloneDeep } from 'lodash';
不再使用 lodash
函数。为什么 Webpack
会使我的 app.bundle.js
膨胀?
我的配置有问题吗?
鉴于标准 lodash
包的现有导出样式,您有两种选择来解决此问题:
- 移动到一个 lodash 包,它以一种可以直接插入导入模式的方式使用导出。正如@alex-rokabilis 在评论中提到的,一个可用的包是 lodash-es
更新您的导入以使用标准
lodash
包使用的导出。如果您查看 lodash's npm page,您会发现它们支持从路径中挑选特定方法。import some from 'lodash/fp/some'; import find from 'lodash/fp/find'; import cloneDeep from 'lodash/fp/cloneDeep';