4. 3.Webpack4-webpack优化

395 阅读3分钟

十九、1.noParse: 不解析不需要的依赖库,减少打包时间

  1. $ mkdir webpack-optimize && cd webpack-optimize && yarn init -y
  2. 安装包: $ cnpm i webpack webpack-cli html-webpack-plugin @babel/core @babel/preset-env babel-loader @babel/preset-react webpack-dev-server -D
  3. webpack.config.js noParse: /jquery/, // 不去解析jquery中的依赖库
let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
  mode: 'development',
  entry: './src/index.js',
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    noParse: /jquery/, // 不去解析jquery中的依赖库
    rules: [
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets:[
              '@babel/preset-env',
              '@babel/preset-react'
            ]
          }
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    })
  ]
}

二十、2.IgnorePlugin:打包时略过的插件

  1. 排除excloud和包含incloud include: path.resolve('src'),exclude: /node_modules/,
  2. 安装包 moment ; 官网:momentjs.com;
  3. webpack.config.js
let webpack = require('webpack');

  plugins: [
    
    new webpack.IgnorePlugin(/\.\/locale/,/moment/), // 不去引用locale语言包
  ]
  1. src/index.js
let moment = require('moment');
import 'moment/locale/zh-cn'; // 单独引用zh-cn语言包,减少打包体积
moment.locale('zh-cn');
let time = moment().endOf('day').fromNow();
console.log(time);

二十一、3.dllPlugin:动态链接库

  1. 安装包react react-dom
  2. 使用
  • index.html
<div id="root"></div>
  • index.js
import React from 'react';
import { render } from 'react-dom';
render(<h1>jsx</h1>, window.root);
  • webpack.config.js
let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let webpack = require('webpack');
module.exports = {
  mode: 'development',
  entry: './src/index.js',
  devServer: {
    port: 3000,
    open: true, 
    contentBase: './dist'
  },
  output: {
    filename: 'bundle.js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve('src'),
        exclude: /node_modules/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              '@babel/preset-react' // 主要靠@babel-react插件实现 独立打包react文件
            ]
          }
        }
      }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new webpack.IgnorePlugin(/\.\/locale/, /moment/),
  ]
}
  1. 独立文件的原理:通过引入js文件,把库通过变量导出到dist目录下
  • 新建文件 webpack.config.test.js test.js
  • webpack.config.test.js
let path = require('path');
module.exports = {
  mode: 'development',
  entry: {
    test: './src/test.js'
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist'), 
    library: 'test', // 通过变量test拿到导出的值 var test = 'kft'
    libraryTarget: 'var' // 默认var , umd、commonjs...
  }
}
  • test.js: module.exports = 'kft'
  • 执行npx webpack --config webpack.config.test.js 通过script导入test.js直接能拿到test = 'kft'
  1. 单独引入react和react-dom
  • 新建 webpack.config.react.js
let path = require('path');
let webpack = require('webpack');
module.exports = {
  mode: 'development',
  entry: {
    react: ['react', 'react-dom']
  },
  output: {
    filename: '_dll_[name].js',
    path: path.resolve(__dirname, 'dist'),
    library: '_dll_[name]',
    // libraryTarget: 'commonjs' // 默认var , umd
  },
  plugins: [
    new webpack.DllPlugin({
      name: '_dll_[name]',
      path: path.resolve(__dirname, 'dist', 'manifest.json')
    })
  ]
}
  • webpack.config.js 添加
let webpack = require('webpack');

  plugins: [
    new webpack.DllReferencePlugin({
      manifest: path.resolve(__dirname, 'dist', 'manifest.json') // 查看manifest.json里是否有单独的库
    }),
    
  ]
  • 在src/index.html引入 <script src="_dll_react.js"></script> *. React render render(jsx,window.root) devServer port open自动打开浏览器 contentBase './dist' 主要靠@babel-react插件实现 独立打包react文件 webpack.config.react.js test.js module.exports = 'kft' webpack.config.react.js path exports entry test.js output filename '[name].js' path dist library ab libraryTarget var react react-dom _dll_[name].js _dll_[name] plugins>.DLLPlugin() name path __dirname 'dist' 'manifest.json' webpack.config.js plugins> .DLLReferencePlugin manifest path.

二十二、4.happypack:多线程打包

  1. 安装包happypack
  2. 在使用loader时分配线程
  • webpack.config.js
let Happypack = require('happypack');

  module: {
    rules: [
      {
        test: /\.js$/,
        include: path.resolve('src'),
        exclude: /node_modules/,
        use: 'Happypack/loader?id=js'
      },
      {
        test: /\.css$/,
        include: path.resolve('src'),
        exclude: /node_modules/,
        use: 'Happypack/loader?id=css'
      }
    ]
  },
  plugins: [
    
    new Happypack({
      id: 'js',
      use: [{
        loader: 'babel-loader',
        options: {
          presets: [
            '@babel/preset-env',
            '@babel/preset-react'
          ]
        }
      }]
    }),
    new Happypack({
      id: 'css',
      use: ['style-loader','css-loader']
    })
  ]  

二十三、5.webpack自带优化:tree-shaking和scope hosting

  1. test.js
let sum = (a, b) => {
  return a + b + 'sum';
}
let minus = (a, b) => {
  return a - b + 'minus';
}
export default {
  sum, minus
}
  1. index.js
// 使用import,在生产环境下打包会自动去除掉没有的代码,tree-shaking es6把没用的代码自动删除
// import calc from './test';
// console.log(calc.sum(1,2)); // 在生产环境下打包,只会打包sum函数,不会的打包minus函数

// let calc  = require('./test'); // es6模块会把结果放到default上
// console.log(calc.default.sum(1,2)); // 在生产环境下,两个方法都会被打包

// 作用域提升 scope hosting 
let a = 1;
let b = 2;
let c = 3;
let d = a + b + c;
console.log(d, '---------------------') // 在webpack中自动省略,可以简化代码,打包后 console.log(6,"---------------------")

二十四、6.抽离公共代码:多页面打包抽离公共代码和第三方插件

  1. +文件
    1. a.js console.log('a~~~~~~~');
    2. b.js console.log('b~~~~~~~');
    3. index.js/other.js import './a'; import './b'; import $ from 'jquery'; console.log($);
  2. webpack.config.js +
  entry: {
    index: './src/index.js',
    other: './src/other.js'
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },  
  optimization: { // commonChunkPlugins
    splitChunks: { // 分割代码块
      cacheGroups: { // 缓存组
        common: { // 公共的模块
          chunks: 'initial',
          minSize: 0,
          minChunks: 2
        },
        verdor: {
          priority: 1, // 权重高,优先抽离出来
          test: /node_modules/, // 把第三方插件抽离出来
          chunks: 'initial',
          minSize: 0,
          minChunks: 2
        }
      }
    }
  },

二十五、7.懒加载

  1. 安装包: @babel/plugin-syntax-dynamic-import
  2. webpack.config.js +
      {
        test: /\.js$/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              '@babel/preset-react'
            ],
            plugins: [
              '@babel/plugin-syntax-dynamic-import'
            ]
          }
        }
      },
  1. src/index.js
let button = document.createElement('button');
button.innerHTML = '点击';
button.addEventListener('click',function(){
  // es6草案中的语法,jsonp实现动态加载文件
  import('./source.js').then((data)=>{
    console.log(data.default);
  })
})
document.body.appendChild(button);
  1. src/source.js
export default 'kft';

二十六、8.热更新:增量更新,不刷新页面

  1. webpack.config.js +
  devServer: {
    hot: true,
    
  },
  plugins: [
  
    new webpack.NamedModulesPlugin(), // 打印更新的模块
    new webpack.HotModuleReplacementPlugin() // 热更新插件
    
  ]  
  1. src/index.js 使用热更新
// import str from './source';
if (module.hot) {
  module.hot.accept('./source', () => {
    let str = require('./source');
    console.log(str)
  })
}

webpack.config.js

let path = require('path');
let HtmlWebpackPlugin = require('html-webpack-plugin');
let webpack = require('webpack');
// let Happypack = require('happypack'); // 多线程打包配置
module.exports = {
  optimization: { // commonChunkPlugins
    splitChunks: { // 分割代码块
      cacheGroups: { // 缓存组
        common: { // 公共的模块
          chunks: 'initial',
          minSize: 0,
          minChunks: 2
        },
        verdor: {
          priority: 1,
          test: /node_modules/, // 把第三方插件抽离出来
          chunks: 'initial',
          minSize: 0,
          minChunks: 2
        }
      }
    }
  },
  mode: 'production',
  entry: {
    index: './src/index.js',
  },
  devServer: {
    // hot: true, // 热更新
    port: 3000,
    open: true,
    contentBase: './dist'
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'dist')
  },
  module: {
    // noParse: /jquery/, // 不去解析jquery中的依赖库
    rules: [
      {
        test: /\.js$/,
        include: path.resolve('src'),
        exclude: /node_modules/,
        // use: 'Happypack/loader?id=js' // 多线程打包配置
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              '@babel/preset-env',
              '@babel/preset-react'
            ],
            plugins: [
              '@babel/plugin-syntax-dynamic-import'
            ]
          }
        }
      },
      {
        test: /\.css$/,
        include: path.resolve('src'),
        exclude: /node_modules/,
        // use: 'Happypack/loader?id=css'
        use: ['style-loader', 'css-loader']
      }
    ]
  },
  plugins: [
    // 动态链接库
    // new webpack.DllReferencePlugin({
    //   manifest: path.resolve(__dirname, 'dist', 'manifest.json')
    // }),

    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    // new webpack.NamedModulesPlugin(), // 打印更新的模块
    // new webpack.HotModuleReplacementPlugin() // 热更新插件

    // new webpack.IgnorePlugin(/\.\/locale/, /moment/), // 打包时略过moment包里的locale

    // 多线程打包
    // new Happypack({
    //   id: 'js',
    //   use: [{
    //     loader: 'babel-loader',
    //     options: {
    //       presets: [
    //         '@babel/preset-env',
    //         '@babel/preset-react'
    //       ]
    //     }
    //   }]
    // }),
    // new Happypack({
    //   id: 'css',
    //   use: ['style-loader','css-loader']
    // })
  ]
}

package.json

{
  "name": "webpack-optimize",
  "version": "1.0.0",
  "description": "",
  "main": "webpack.config.js",
  "scripts": {
    "build": "webpack --config webpack.config.js",
    "dev": "webpack-dev-server"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "@babel/core": "^7.4.5",
    "@babel/plugin-syntax-dynamic-import": "^7.2.0",
    "@babel/preset-env": "^7.4.5",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.6",
    "css-loader": "^3.0.0",
    "happypack": "^5.0.1",
    "html-webpack-plugin": "^3.2.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "style-loader": "^0.23.1",
    "webpack": "^4.35.2",
    "webpack-cli": "^3.3.5",
    "webpack-dev-server": "^3.7.2"
  },
  "dependencies": {
    "jquery": "^3.4.1",
    "moment": "^2.24.0"
  }
}