【问题标题】:Tree-shaking nested modules with webpack 4使用 webpack 4 的 tree-shaking 嵌套模块
【发布时间】:2019-02-08 13:33:35
【问题描述】:

无法找出为什么 tree-shaking 没有像我预期的那样工作...... 我的目标是建立一个tree-shak-able 库。

  • index.js
    • 标题
    • 按钮 => 按钮组

我有一个使用这个库的 webpack 应用程序。当我只导入 Header 组件时,Button 模块按预期删除,但我的 webpack 包包含 ButtonGroup 组件。

有人能解释为什么吗? 如果可能的话,如何从 webpack 构建中摇树嵌套组件?

谢谢

汇总和库配置

rollup.config.js

import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import replace from 'rollup-plugin-replace';

export default {
  input: './src/index.js',
  output: {
    name: 'ui-component',
    sourcemap: true, 
    sourcemapFile: 'ui-component',
    format: 'es',
    file: 'build/ui-component.module.js',
  },
  plugins: [
    replace({
      'process.env.NODE_ENV': JSON.stringify('production')
    }),
    resolve({
        extensions: [ '.js', '.jsx', '.json' ]  
    }),
    commonjs(),
    babel({
      exclude: 'node_modules/**',
    })
  ],
  external: ['react', 'react-dom']
};

index.js

export * from './Button';
export * from './Header';

Header.jsx - 简单的反应组件

import React, { Component } from 'react';

export class Header extends Component {
  render() {
    return (
      <div style={ { padding: '3px 7px' } }>
        <span>{this.props.children}</span>
      </div>
    )
  }
}

Button.jsx - 反应组件

import React, { Component } from 'react';
import { ButtonGroup } from './ButtonGroup';

class Button extends Component {

    constructor(props) {
        super(props);
    }

    render() {
        const display = 'button';
        return (
            <ButtonGroup>
                <a> {display} </a>
            </ButtonGroup>
        );
    }
}

export { Button } 

还有我的 webpack 配置和构建:

webpack.config

const path    = require('path');
const express = require('express');

module.exports = {
  mode: 'production',
  devtool: false,
  optimization: {
    sideEffects: false
  },
  entry: {
    index: './src/App.jsx'
  },
  output: {
    filename: '[name].bundle.js',
    path: path.resolve(__dirname, './bundle/')
  },
  resolve: {
    extensions: ['.js', '.jsx'],
    alias: {
      'ui-component': path.resolve(__dirname, '../') 
    }
  },
  module: {
    rules: [
      {
        test: /\.(jsx|js)$/,
        include: [
          path.resolve(__dirname, 'src'), 
          path.resolve(__dirname, '../') 
        ],   
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [ "@babel/env", { "modules": false}],
              [ "@babel/react" ]
            ],
            plugins: [
              ["@babel/plugin-proposal-object-rest-spread"],
              ["@babel/plugin-proposal-class-properties"] 
            ]
          }
        }
      },
      {
        test: /\.css$/,
        use: [ 'style-loader', 'css-loader' ]
      },
      {
        test: /\.(eot|svg|ttf|woff|woff2)$/,
        use: [ 'url-loader' ]
      }
    ]
  },
  externals: {
    react: 'React',
    'react-dom': 'ReactDOM'
  },
  devServer: {
    contentBase: './',
    publicPath: '/build',
    port: 8080,
    before(app) {
      app.use('/build', express.static(path.resolve(__dirname, '../build/')))
    }
  }
};

* App.jsx *

import React from 'react';
import ReactDOM from 'react-dom';
import { Header } from 'ui-component';

class App extends React.Component {
  render() {
    return (
      <div>
        <Header >
          header only
        </Header>
      </div>
    );
  }
}


ReactDOM.render(
  <App />, document.getElementById('app')
)

* 构建状态 *

single entry ./src/App.jsx  index
     | ./src/App.jsx 751 bytes [depth 0] [built]
     |     [no exports]
     |     ModuleConcatenation bailout: Module is an entry point
     |     single entry ./src/App.jsx  index
     | ../build/ui-component.module.js 1.43 KiB [depth 1] [built]
     |     [exports: Button, Header]
     |     [only some exports used: Header]
     |     harmony side effect evaluation ui-component  ./src/App.jsx 5:0-38
     |     harmony import specifier ui-component  ./src/App.jsx 19:64-70

* 构建输出 *

e.prototype.render=function(){return o.a.createElement("div",null,"Groups")},e}

【问题讨论】:

  • 你使用的是哪个 webpack 版本? 4.17.0 之前的 webpack 在消除死代码方面确实存在错误。
  • "webpack": "^4.17.1"
  • @poulpo 你找到解决方案了吗?

标签: javascript reactjs webpack rollupjs tree-shaking


【解决方案1】:

如果你不想要按钮,请像这样导入它 import Header from 'ui-component/Header'; 或添加 "sideEffects": false 在 "ui-component" 的 package.json 中; https://github.com/webpack/webpack/tree/master/examples/side-effects

【讨论】:

  • 我已经有 sideEffects: false 里面的 ui-comp 包。当我导入 Header 时,我没有 Button 模块,但是 ButtonGroup 模块没有从最终包中删除。
【解决方案2】:

我在嵌套模块和重新导出时也遇到过这个问题(为了简化代码维护而进行的两层重新导出 - 减少了对主入口点文件的接触)。

Webpack 目前还不能(很好)处理这种情况,但看起来 Webpack v5 会:https://github.com/webpack/webpack/pull/9203

【讨论】:

    猜你喜欢
    • 2019-02-14
    • 2019-01-28
    • 2021-11-18
    • 2018-05-19
    • 2018-06-29
    • 1970-01-01
    • 2017-11-24
    • 2020-05-19
    • 2018-04-29
    相关资源
    最近更新 更多