2017-06-21 78 views
0

我想縮小我的webpack包,因爲現在第一次加載網站大約需要25秒。 app.bundle.js是11,989KB,vendor.bundle.js是1,842KB 我自己的代碼只有幾KB。 當我檢查app.bundle.js的內容大部分的空間是由外部庫(react-dom,moment,react-bootstrap ...)所採用的無法使webpack縮小包

所以我試圖縮小它們,但是有些原因,我所嘗試的一切都不起作用。

我不是webpack的專家,所以更多有知識的人的幫助將會非常受歡迎。

注:我使用的webpack文件來自另一個項目,我使用了一個示例。所以它可能不完美配置。

這裏是我的package.json:

{ 
    "name": "myproject", 
    "version": "0.1.0", 
    "description": "a description.", 
    "private": true, 
    "devDependencies": { 
    "babel-plugin-react-html-attrs": "^2.0.0", 
    "babel-plugin-transform-runtime": "^6.15.0", 
    "babel-polyfill": "^6.16.0", 
    "babel-preset-stage-2": "^6.18.0", 
    "babili-webpack-plugin": "^0.1.1", 
    "compression-webpack-plugin": "^0.4.0", 
    "react-hot-loader": "^1.3.1", 
    "react-scripts": "0.9.2", 
    "serve-favicon": "^2.3.2", 
    "webpack-dev-server": "^2.4.1", 
    "webpack-hot-middleware": "^2.13.2" 
    }, 
    "dependencies": { 
    "axios": "^0.15.2", 
    "babel-core": "^6.2.1", 
    "babel-loader": "^6.2.0", 
    "babel-plugin-transform-class-properties": "^6.18.0", 
    "babel-plugin-transform-decorators-legacy": "^1.3.4", 
    "babel-plugin-transform-runtime": "^6.15.0", 
    "babel-polyfill": "^6.16.0", 
    "babel-preset-es2015": "^6.1.18", 
    "babel-preset-react": "^6.1.18", 
    "babel-preset-stage-0": "^6.3.13", 
    "babel-preset-stage-2": "^6.3.13", 
    "circular-dependency-plugin": "^2.0.0", 
    "classnames": "^2.2.1", 
    "clean-webpack-plugin": "^0.1.9", 
    "copy-webpack-plugin": "^4.0.1", 
    "css-loader": "^0.26.2", 
    "dotenv": "^4.0.0", 
    "es6-promise": "^4.0.5", 
    "file-loader": "^0.10.1", 
    "firebase": "^3.6.0", 
    "history": "^4.5.1", 
    "immutable": "^3.8.1", 
    "invariant": "^2.2.0", 
    "isomorphic-fetch": "^2.2.1", 
    "jsonwebtoken": "^7.2.1", 
    "less-loader": "^2.2.0", 
    "moment": "^2.11.1", 
    "react": "^15.4.2", 
    "react-addons-css-transition-group": "^15.4.2", 
    "react-async-script": "^0.7.0", 
    "react-bootstrap": "^0.30.7", 
    "react-dnd": "^2.0.2", 
    "react-dnd-html5-backend": "^2.0.2", 
    "react-dom": "^15.4.2", 
    "react-fontawesome": "^1.5.0", 
    "react-google-recaptcha": "^0.6.0", 
    "react-gravatar": "^2.2.2", 
    "react-helmet": "^4.0.0", 
    "react-input-range": "^1.0.2", 
    "react-modal": "^1.5.2", 
    "react-page-click": "^3.0.0", 
    "react-recaptcha": "^2.2.6", 
    "react-redux": "^5.0.3", 
    "react-router": "^3.0.2", 
    "react-router-redux": "^4.0.0", 
    "redux": "^3.0.4", 
    "redux-form": "^6.2.0", 
    "redux-logger": "^2.3.2", 
    "redux-thunk": "^2.2.0", 
    "rimraf": "^2.5.4", 
    "single-module-instance-webpack-plugin": "0.0.4", 
    "style-loader": "^0.13.2", 
    "superagent": "^3.5.0", 
    "webpack": "^2.2.1", 
    "xml2js": "^0.4.17", 
    "xmldom": "^0.1.27", 
    "xpath": "0.0.23" 
    }, 
    "scripts": { 
    "start": "node devServer.js --progress --verbose", 
    "clean": "rimraf ./dist", 
    "dev": "webpack -d --watch --progress --display-error-details --display-reasons", 
    "start1": "webpack-dev-server --config ./webpack.config.comphotdeploy -d --progress --colors --host localhost --port 28080 --hot --inline --content-base src", 
    "builddev": "webpack -d --progress --display-error-details --display-reasons", 
    "build": "webpack -p --progress --verbose", 
    "dist": "rimraf ./dist&&webpack -d --display-error-details --display-reasons", 
    "start-react": "SET PORT=9999&&SET DEVTOOL=source-map&&react-scripts start", 
    "build-react": "react-scripts build", 
    "test": "react-scripts test --env=jsdom", 
    "eject": "react-scripts eject" 
    }, 
    "eslintConfig": { 
    "extends": "./node_modules/react-scripts/config/eslint.js" 
    } 
} 

而且我的WebPack:

var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 

var webpack = require('webpack'); 
var path = require('path'); 

var ProvidePlugin = require("webpack/lib/ProvidePlugin"); 
var CommonsChunkPlugin = require("webpack/lib/optimize/CommonsChunkPlugin"); 
var LimitChunkCountPlugin = require("webpack/lib/optimize/LimitChunkCountPlugin"); 
var DedupePlugin = require("webpack/lib/optimize/DedupePlugin"); 
var SingleModuleInstancePlugin = require('single-module-instance-webpack-plugin'); 
var CleanWebpackPlugin = require('clean-webpack-plugin'); 
var CopyWebpackPlugin = require('copy-webpack-plugin'); 
var CircularDependencyPlugin = require('circular-dependency-plugin'); 

var BUILD_DIR = path.resolve(__dirname,'dist'); 

var APP_DIR = path.resolve(__dirname, 'src'); 

const BabiliPlugin = require('babili-webpack-plugin'); 

// http://dev.topheman.com/make-your-react-production-minified-version-with-webpack/ 
// https://medium.com/@rajaraodv/two-quick-ways-to-reduce-react-apps-size-in-production-82226605771a 
// https://hackernoon.com/tricks-to-minimize-react-js-build-file-size-a35e355b8c64 
var CompressionPlugin = require('compression-webpack-plugin'); 

// Load environment variables from .env file. Suppress warnings using silent 
// if this file is missing. dotenv will never modify any environment variables 
// that have already been set. 
// https://github.com/motdotla/dotenv 
require('dotenv').config({silent: true}); 

var PrintChunksPlugin = function() {}; 
PrintChunksPlugin.prototype.apply = function(compiler) { 
    compiler.plugin('compilation', function(compilation, params) { 
     compilation.plugin('after-optimize-chunk-assets', function(chunks) { 
      console.log(chunks.map(function(c) { 
       return { 
        id: c.id, 
        name: c.name 
/*, 
        includes: c.modules.map(function(m) { 
         return m.request; 
        }) 
*/ 
       }; 
      })); 
     }); 
    }); 
}; 

var config = { 
    devtool: 'cheap-module-source-map', 
    entry: { 
     app: APP_DIR + '/index.js', 
     vendor: [ 
      'react', 
      'react-dom' 
     ] 
    }, 

    output: { 
     path:BUILD_DIR, 
     filename: "[name].bundle.js", 
     chunkFilename: "[name]-chunk.js", 
     publicPath: BUILD_DIR 
    }, 

    watch: false, 
    watchOptions: { 
    poll: true, 
    aggregateTimeout: 300, 
    number: 1000 
    }, 
    module : { 
     loaders : [ 
      { 
       test : /\.jsx?/, 
       include : APP_DIR, 
       exclude: /node_modules/, 
       loaders: ['react-hot-loader', 'babel-loader?' + JSON.stringify({ 
       cacheDirectory: true, 
       plugins: [ 
        'transform-runtime', 
        'react-html-attrs', 
        'transform-class-properties', 
        'transform-decorators-legacy' 
       ], 
       presets: [ 
        [ 
         "es2015", 
         { 
          "modules": false 
         } 
        ], 
        'react', 
        'stage-2'] 
       })] 
      }, 

      // CSS 
      // "css" loader resolves paths in CSS and adds assets as dependencies. 
      // "style" loader turns CSS into JS modules that inject <style> tags. 
      // In production, we use a plugin to extract that CSS to a file, but 
      // in development "style" loader enables hot editing of CSS. 
      { 
       test: /\.css$/, 
       include: path.join(__dirname, 'src/style'), 
       loader: 'style-loader!css-loader' 
      }, 
      // "file" loader makes sure those assets get served by WebpackDevServer. 
      // When you `import` an asset, you get its (virtual) filename. 
      // In production, they would get copied to the `build` folder. 
      { 
       test: /\.(ico|jpg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/, 
       exclude: /\/favicon.ico$/, 
       loader: 'file-loader', 
       query: { 
       name: '[path][name][hash].[ext]', 
       publicPath: '/' 
       } 
      }, 
      { 
       test: /\.(ico)(\?.*)?$/, 
       exclude: /node_modules/, 
       loader: 'file-loader', 
       query: { 
        name: './images/[name].[ext]' 
       } 
      } 
     ] 
    }, 

    // use EnableCircularDependencyPlugin=true|false to check the option 
    plugins: [ 
     new webpack.DefinePlugin({ 
      // A common mistake is not stringifying the "production" string. 
      'process.env': { 'NODE_ENV': JSON.stringify('production') }, 

      // DISABLE redux-devtools HERE 
      __DEVTOOLS__: false 
     }), 

     // minify everything 
     new webpack.optimize.UglifyJsPlugin({ 
      compressor: { 
       warnings: false 
      } 
     }), 

     // Merge chunks 
     new webpack.optimize.AggressiveMergingPlugin(), 

     /* 
     new CompressionPlugin({ 
      asset: "[path].gz[query]", 
      algorithm: "gzip", 
      test: /\.js$|\.css$|\.html$/, 
      threshold: 10240, 
      minRatio: 0.8 
     }), 
     */ 

     // new BabiliPlugin(), 

     new CopyWebpackPlugin([ 
      { from: APP_DIR + '/index.html', to: BUILD_DIR + '/index.html' }, 
      { from: APP_DIR + '/images/favicon.ico', to: BUILD_DIR + '/images/favicon.ico' }, 
      { from: APP_DIR + '/images/favicon.png', to: BUILD_DIR + '/images/favicon.png' }, 
      { from: APP_DIR + '/images/favicon-16x16.png', to: BUILD_DIR + '/images/favicon-16x16.png' }, 
      { from: APP_DIR + '/images/favicon-32x32.png', to: BUILD_DIR + '/images/favicon-32x32.png' }, 
      { from: APP_DIR + '/images/favicon-48x48.png', to: BUILD_DIR + '/images/favicon-48x48.png' }, 
      { from: APP_DIR + '/images/favicon-57x57.png', to: BUILD_DIR + '/images/favicon-57x57.png' }, 
      { from: APP_DIR + '/images/favicon-60x60.png', to: BUILD_DIR + '/images/favicon-60x60.png' }, 
      { from: APP_DIR + '/images/favicon-72x72.png', to: BUILD_DIR + '/images/favicon-72x72.png' }, 
      { from: APP_DIR + '/images/favicon-76x76.png', to: BUILD_DIR + '/images/favicon-76x76.png' }, 
      { from: APP_DIR + '/images/favicon-96x96.png', to: BUILD_DIR + '/images/favicon-96x96.png' }, 
      { from: APP_DIR + '/images/favicon-114x114.png', to: BUILD_DIR + '/images/favicon-114x114.png' }, 
      { from: APP_DIR + '/images/favicon-120x120.png', to: BUILD_DIR + '/images/favicon-120x120.png' }, 
      { from: APP_DIR + '/images/favicon-144x144.png', to: BUILD_DIR + '/images/favicon-144x144.png' }, 
      { from: APP_DIR + '/images/favicon-152x152.png', to: BUILD_DIR + '/images/favicon-152x152.png' }, 
      { from: APP_DIR + '/images/favicon-160x160.png', to: BUILD_DIR + '/images/favicon-160x160.png' }, 
      { from: APP_DIR + '/images/favicon-180x180.png', to: BUILD_DIR + '/images/favicon-180x180.png' }, 
      { from: APP_DIR + '/images/favicon-192x192.png', to: BUILD_DIR + '/images/favicon-192x192.png' } 
      ]), 

     //new BundleAnalyzerPlugin({analyzerMode: 'static'}), 
     //new PrintChunksPlugin() 
    ], 

     /* 
      new webpack.HotModuleReplacementPlugin(), 

      new webpack.NoEmitOnErrorsPlugin(), 

      new webpack.optimize.CommonsChunkPlugin({ 
       name: 'permateam-core', 
       minChunks(module, count) { 
        var context = module.context; 
        return context && context.indexOf('src\\') >= 0; 
       }, 
      }), 

      new webpack.optimize.CommonsChunkPlugin({ 
       name: 'react-build', 
       minChunks(module, count) { 
        var context = module.context; 
        return context && (context.indexOf('node_modules\\react\\') >= 0 || context.indexOf('node_modules\\react-dom\\') >= 0); 
       }, 
      }), 

      new webpack.optimize.CommonsChunkPlugin({ 
       name: 'manifest' 
      }), 

      // uglfy/minify js 
      new webpack.optimize.OccurrenceOrderPlugin(), 
      new webpack.optimize.UglifyJsPlugin({ 
       mangle: true, 
       compress: { 
        warnings: false, // Suppress uglification warnings 
        pure_getters: true, 
        unsafe: true, 
        unsafe_comps: true, 
        screw_ie8: true 
       }, 
       output: { 
        comments: false, 
       }, 
       exclude: [/\.min\.js$/gi] // skip pre-minified libs 
      }), 

      new BundleAnalyzerPlugin({analyzerMode: 'static'}), 
      //new PrintChunksPlugin(), 

     //*********************************** async chunks************************* 

     //catch all - anything used in more than one place 
     new webpack.optimize.CommonsChunkPlugin({ 
      async: 'used-twice', 
      minChunks(module, count) { 
       return count >= 2; 
      }, 
     }), 

     //specifically bundle these large things 
     new webpack.optimize.CommonsChunkPlugin({ 
      async: 'react-dnd', 
      minChunks(module, count) { 
       var context = module.context; 
       var targets = ['react-dnd', 'react-dnd-html5-backend', 'react-dnd-touch-backend', 'dnd-core'] 
       return context && context.indexOf('node_modules') >= 0 && targets.find(t => new RegExp('\\\\' + t + '\\\\', 'i').test(context)); 
      }, 
     }), 

     return plugins; 
    })(), 
    */ 

    node: { 
     net: 'empty', 
     dns: 'empty' 
    } 
}; 

module.exports = config; 
+0

您是否嘗試打開bundle.js文件並檢查以確定它們是否已被縮小? 'new webpack.DefinePlugin({'process.env':{ NODE_ENV:JSON.stringify('production') } })'應該縮小它 – Hoyen

+0

是的。 這是app.bundle.js中的內容示例 'function translate(number,withoutSuffix,key){\ n var result = number +''; \ n switch(key){\ n case'm' :\ n返回withoutSuffix? 'minuta':'minutę'; \ n case'mm':\ n返回結果+(複數(number)?'minuty':'minut'); \ n案例'h':\ n返回withoutSuffix? 'godzina':'godzinę'; \ n case'hh':\ n返回結果+(複數(number)?'godziny':'godzin'); \ n case'MM':\ n return result +(plural號碼)?'miesiące':'miesię' –

回答

0

我發現如何解決這個問題,即使我不明白爲什麼問題發生。

我是做

NPM運行DIST

現在

我做

NPM運行建立

現在app.bundle.js是1765 KB和vendor.bundle.js是151KB

我仍然有一些優化來進一步縮小app.bundle.js,但這已經是一個好的開始。

我仍然想知道爲什麼minify不能與dist一起工作,如果有人有想法。