Webpack高级概念

一.  Tree Shaking 概念详解

1、接着上次的代码

index.js:

import '@babel/polyfill';

import React, { Component } from 'react';
import ReactDom from 'react-dom';

class App extends Component {
  render() {
    return <div>hello world</div>
  }
}

ReactDom.render(<App />, document.getElementById('root'));

实际上当前版本的Webpack比较新,如果在webpack.config.js里面配置了babel-loader的相关内容(其实我们已经把它移到.babelrc这个文件中了),如果我们对presets下的useBuiltIns设置了usage这样的一个配置参数的话。那么我们index.js文件中不去引入babel/polyfill也是可以的。

 

2、

目录:

index.js:

import {add} from './math.js';

add(1, 2);

math.js:

export const add = (a, b) => {
  console.log(a + b);
}

export const minus = (a, b) => {
  console.log(a - b);
}

执行npx webpack,控制台打印出3。但是我们去main.js里面发现我们没有import的minus方法也打包了。这是没有必要的,因为我们的业务代码只引入了add方法,将minus也打包会导致打包后的main.js过大。最理想的打包方式就是我们引入什么就打包什么。解决办法:

webpack在2.0版本以后提出了Tree shaking这个概念:实际上就是把一个模块里没用的东西都摇晃(shaking表示摇晃)掉。一个模块可以理解成一个树,比如说math.js文件是一个模块,里面会导出很多的内容,这些内容可以理解成一个小的树形结构。而我们在index.js中只引入树的一部分,只需要把引入的那一部分打包即可。

注意: Tree-shaking只支持ES module模块引入的方式引入。

配置Webpack.config.js:

mode设置成 'development'的时候是没有Tree shanking这个功能的,所以我们需要自己配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',
  entry: {
    main: './src/index.js'
  },
  devServer: {
    contentBase: './dist',
    port: 10000,
    hot: true
  },
  module: {
    rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      loader:'babel-loader',
    },
    {
      test: /\.(jpg|png|gif)$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 10240
        }
      }
    }, {
      test: /\.scss$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: [
        'style-loader',
        'css-loader',
        'postcss-loader'
      ]
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'src/index.html'
    }),
    new CleanWebpackPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ],
  optimization: {    //在开发环境中配置Tree shaking
    usedExports: true    //意思就是去打包引入的模块
  },
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  }
}

package.json:

小知识:

 

{
  "name": "webpackDemo",
  "sideEffects": false,
  "version": "1.0.0",
  "description": "",
  "main": "postcss.config.js",
  "dependencies": {
    "@babel/polyfill": "^7.4.4",
    "@babel/runtime-corejs2": "^7.5.4",
    "autoprefixer": "^9.6.1",
    "clean-webpack-plugin": "^3.0.0",
    "core-js": "^3.1.4",
    "css-loader": "^3.0.0",
    "file-loader": "^4.0.0",
    "html-webpack-plugin": "^3.2.0",
    "node-sass": "^4.12.0",
    "postcss-loader": "^3.0.0",
    "react": "^16.8.6",
    "react-dom": "^16.8.6",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "url-loader": "^2.0.1",
    "webpack": "^4.35.3",
    "webpack-cli": "^3.3.5",
    "webpack-dev-server": "^3.7.2"
  },
  "private": true,
  "devDependencies": {
    "@babel/core": "^7.5.4",
    "@babel/plugin-transform-runtime": "^7.5.0",
    "@babel/preset-env": "^7.5.4",
    "@babel/preset-react": "^7.0.0",
    "babel-loader": "^8.0.6"
  },
  "scripts": {
    "start": "webpack-dev-server"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

"sideEffects": false,  意思是比如index.js中引入了babel/polyfill文件,由于它没有导出任何东西,用了Tree-shaking后导致打包会忽略它。因为当前index.js中没有引入像babel/polyfill这样的包,所以设置成false。表示没有需要特殊处理的东西。

重新执行打包,发现还是把minus给打包了,这是因为在开发环境中生成的代码需要做一些调试,如果Tree-shaking把一些代码删除掉的话

,在做调试的时候,代码对应的sourcemap的行数就都错了。所以Tree-shaking还是会保留这些代码。不过从下图可以看出,它已经提示我们了导出的只用了add这个模块。

 

production环境下:此时Tree-shaking就会生效了。配置如下:

webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const webpack = require('webpack');

module.exports = {
  mode: 'production',
  devtool: 'cheap-module-source-map',
  entry: {
    main: './src/index.js'
  },
  devServer: {
    contentBase: './dist',
    port: 10000,
    hot: true
  },
  module: {
    rules: [
    {
      test: /\.js$/,
      exclude: /node_modules/,
      loader:'babel-loader',
    },
    {
      test: /\.(jpg|png|gif)$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 10240
        }
      }
    }, {
      test: /\.scss$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: [
        'style-loader',
        'css-loader',
        'postcss-loader'
      ]
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: 'src/index.html'
    }),
    new CleanWebpackPlugin(),
    new webpack.HotModuleReplacementPlugin()
  ],
  //该模式下Tree-shaking的配置自动就会写好了,我们不用自己配webpack.config.js
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, 'dist')
  }
}

再次执行打包后发现Tree-shaking就生效了:

 


二. Develoment 和 Production 模式的区分打包

1、当我们项目开发完毕,就需要使用 production模式打包上线。两种打包模式的差异:

  • 开发环境中sourcemap是非常全的,这样的话再开发环境下能够帮我们快速的定位问题。production模式下,由于已经要上线了,此时sourcemap就不是那么重要了,此时的sourcemap会更加简洁一些或者我们通过生成一个.map文件来进行存储。
  • 开发环境下我们的代码不需要进行压缩,方便我们查看打包后的代码。一旦代码要上线,此时我们就希望代码被压缩,所以production模式下代码是被压缩过的。

2、我们切换两种模式的时候,需要经常修改webpack.config.js文件,这样很麻烦。解决办法:

  • 首先将 development 模式下的 webpack 配置文件命名为 webpack.dev.js 。
  • 在根目录下新建一个 webpack.prod.js 文件,里面放置我们线上环境下的webpack配置代码。

webpack.dev.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); 

module.exports = {
  mode: 'development',
  entry: './src/index.js',
  devtool: 'cheap-module-eval-source-map',
  devServer: {
    contentBase: './dist',
    port: 10000
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    }, {
      test: /\.jpg$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 2048
        }
      }
    }, {
      test: /\.scss$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: ['style-loader', 'css-loader', 'postcss-loader']
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ],
  optimization: {    //在开发环境中配置Tree shaking
    usedExports: true    //意思就是去打包引入的模块
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  }
}

webpack.prod.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); 

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  devtool: 'cheap-module-source-map',
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    }, {
      test: /\.jpg$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 2048
        }
      }
    }, {
      test: /\.scss$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: ['style-loader', 'css-loader', 'postcss-loader']
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  }
}

package.json:

dev: 如果要启动devserver进行开发的话,那么就是使用开发环境的webpack配置

build: 如果打包线上文件的话,就使用webpack.prod.js这个配置

此时运行npm run dev,进行的是开发环境的webpack打包配置。运行npm run build,执行的是生产环境的打包配置。

 

3、上面的两种打包方案的文件中存在大量的重复代码,优化方案:

  • 根目录下创建webpack.common.js文件。
  • 将两者共有的代码都赋值到该文件下,并将之前两个文件共有的代码删除。
  • 引入一个第三方模块: cnpm install webpack-merge -D,帮助我们将common的代码和两个打包文件代码做一个融合。

webpack.common.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); 

module.exports = {
  entry: './src/index.js',
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    }, {
      test: /\.jpg$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 2048
        }
      }
    }, {
      test: /\.scss$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: ['style-loader', 'css-loader', 'postcss-loader']
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: '[name].js'
  }
}

webpack.dev.js:

const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');

const devConfig = {
  mode: 'development',
  devtool: 'cheap-module-eval-source-map',
  devServer: {
    contentBase: './dist',
    port: 10000
  },
  optimization: {    //在开发环境中配置Tree shaking
    usedExports: true    //意思就是去打包引入的模块
  }
}

module.exports = merge(commonConfig, devConfig);   //将自有的和公共的做一个结合

webpack.prod.js:

const merge = require('webpack-merge');
const commonConfig = require('./webpack.common.js');

const prodConfig = {
  mode: 'production',
  devtool: 'cheap-module-source-map'
}

module.exports = merge(commonConfig, prodConfig);

此时能够正常进行两种不同方案的打包。

注意:如果将三个文件都放在一个文件夹下面,此时package.json文件的命令路径需要修改,比如在build文件夹下:

"dev": "webpack-dev-server --config ./build/webpack.dev.js"

此时应该修改output配置:


三. Webpack 和 Code Splitting

Code Splitting:指的是代码分割。

此时的目录结构:

因为我们希望查看打包后的文件代码,所以不能用npm run dev来打包,添加命令:

 

1、例子

  • 安装一个插件:cnpm install lodash --save  它是一个功能集合,提供很多方法,可以高性能地去帮助我们使用字符串拼接的一些函数等。
  • index.js添加代码:
import _ from 'lodash';

console.log(_.join(['a', 'b', 'c']));   //a,b,c

打包后打印出a,b,c。

假如我们index.js的业务逻辑很多,打包的话会把工具库和业务逻辑都打包到main.js文件中。此时虽然也能正常运行,但是main.js会比较大,导致加载时间很长。还有就是假如我们修改了业务代码,用户要重新去加载main.js,此时又要等很长的时间,这样就导致用户体验很差。

解决办法:

  • src目录下新建一个lodash.js文件,添加代码:
import _ from 'lodash';

window._ = _;  //加载了一个lodash,又将lodash挂载到了全局的下划线上面,这样的话我们在其它地方就可以是使用下划线这个变量了。
  • index.js:
console.log(_.join(['a', 'b', 'c']));   //a,b,c
  • webpack.common.js添加配置:
  entry: {
    lodash: './src/lodash.js',
    main: './src/index.js'
  }

再次打包,运行正常。

此时打包后分成了两个js文件,这带来的好处就是当我们修改了业务代码,用户只需要加载打包后的业务js代码即可,不用加载库的代码。

在项目中对代码公用部分进行拆分来提升项目运行的速度,也就是Code Splitting。

 

2、上面的例子我们是自己做的公用代码拆分,它不够智能。webpack通过它自带的一些插件可以智能地帮助我们做一些拆分工作。

  • 删除lodash.js文件,修改index.js文件:
import _ from 'lodash';
console.log(_.join(['a', 'b', 'c']));   //a,b,c
  • 添加weback.common.js配置:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); 

module.exports = {
  entry: {
    main: './src/index.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    }, {
      test: /\.jpg$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 2048
        }
      }
    }, {
      test: /\.scss$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: ['style-loader', 'css-loader', 'postcss-loader']
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ],
  optimization: {
    splitChunks: {
      chunks: 'all'   //意思就是我要帮你去做代码分割了
    }
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].js'
  }
}

此时执行npm run dev-build打包命令,发现dist文件夹下面打包了两个js文件,一个是业务逻辑js,还有一个是类库js。

这种代码分割配置适合上面这种同步模块的分割。

3、webpack中的代码分割不仅仅适合上面这种同步模块的分割。异步的代码也能进行分割,而且不需要添加上面的那种配置就会自动进行。

index.js:

function getComponent() {
  return import('lodash').then(( { default: _ } ) => {
    var element = document.createElement('div');
    element.innerHTML = _.join(['z', 't'], '-');
    return element;
  })
};

getComponent().then( element => {
  document.body.appendChild(element);
});

webpack.config.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); 

module.exports = {
  entry: {
    main: './src/index.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    }, {
      test: /\.jpg$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 2048
        }
      }
    }, {
      test: /\.scss$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: ['style-loader', 'css-loader', 'postcss-loader']
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ],
  // optimization: {
  //   splitChunks: {
  //     chunks: 'all'   //意思就是我要帮你去做代码分割了
  //   }
  // },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].js'
  }
}

执行打包命令,此时webpack对于这种异步的代码也能智能地进行分割。

 


四. SplitChunksPlugin 配置参数详解

webpack的代码分割底层使用了SplitChunksPlugin这个插件。

上面打包之后的dist文件夹:

1、 我们希望把 0.js 改一个名字

  • 修改index.js文件:
function getComponent() {
  //下面的意思就是异步地引入lodash这样一个库,当我做代码分割的时候,单独给lodash进行打包的时候,给它起个名字叫lodash
  return import(/* webpackChunkName: "lodash" */'lodash').then(( { default: _ } ) => {
    var element = document.createElement('div');
    element.innerHTML = _.join(['z', 't'], '-');
    return element;
  })
};

getComponent().then( element => {
  document.body.appendChild(element);
});
  • 安装一个插件帮我们识别上面那种魔法字符串写法:cnpm install --save-dev @babel/plugin-syntax-dynamic-import
  • .babelrc添加配置:
{
  "presets":[
    [
      "@babel/preset-env",
      {
        "useBuiltIns": "usage"
      }
    ],
    "@babel/preset-react"
  ],
  "plugins": ["@babel/plugin-syntax-dynamic-import"] 
}

执行 npm run dev-build 命令后,

打包的lodash.js文件名却不是我们给的那个,修改webpack.common.js配置:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); 

module.exports = {
  entry: {
    main: './src/index.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    }, {
      test: /\.jpg$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 2048
        }
      }
    }, {
      test: /\.scss$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: ['style-loader', 'css-loader', 'postcss-loader']
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ],
  optimization: {
    splitChunks: {
      chunks: 'all',   //意思就是我要帮你去做代码分割了
      cacheGroups: {
        vendors: false,
        default: false
      }
    }
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].js'
  }
}

执行打包命令后,dist文件夹下:

 

2、SplitChunks配置介绍:

splitChunks: {
    chunks: "async",  //在做代码分割的时候,只对异步代码生效。
    minSize: 30000,   //发现引入的块大于30000个字节的话,就会帮我们做代码分割
    minChunks: 1,     //当一个Chunk被至少用了多少次的时候,才对他进行代码分割
    maxAsyncRequests: 5,  //同时加载的模块数,最多是5个
    maxInitialRequests: 3,  //整个网站首页进行加载的时候,或者说入口文件进行加载的时候,入口文件可能会引入其它的js文件,入口文件如果做代码分割,最多只能分割出3个。此处一般不修改
    automaticNameDelimiter: '~',  //组和文件名之间连接的符号
    name: true,   //打包生成的名字通过cacheGroup设置有效。此处一般不变
    cacheGroups: {  //如果都符合下面俩个组的要求,那么谁的priority值大,就用谁的
        vendors: {  //vendors组
            test: /[\\/]node_modules[\\/]/,   //如果是从node_modules引入的
            priority: -10
        },
    default: {      //这个组里面没有test,意思就是所有的模块都符合要求
            minChunks: 2,
            priority: -20,
            reuseExistingChunk: true  //如果一个模块已经被打包了,再打包就会忽略这个模块,直接使用之前使用的那么模块就可以
        }
    }
}

对同步的代码进行分割:

splitChunks: {
    chunks: "all",   //1  同步和异步代码都会做分割,initial表示对同步代码做分割
    minSize: 30000,
    minChunks: 1,
    maxAsyncRequests: 5,
    maxInitialRequests: 3,
    automaticNameDelimiter: '~',
    name: true,
    cacheGroups: {
        vendors: {  //2
            test: /[\\/]node_modules[\\/]/,
            priority: -10,
            filename: 'vendors.js'    //打包后的名字不带main,只有vendors
        },
        default: false   
    }
}

 


五. Lazy Loading 懒加载,Chunk 是什么?

1、实现一个懒加载的行为

index.js:

function getComponent() {
  return import(/* webpackChunkName: "lodash" */'lodash').then(( { default: _ } ) => {
    var element = document.createElement('div');
    element.innerHTML = _.join(['z', 't'], '-');
    return element;
  })
};

document.addEventListener('click', () => {
  getComponent().then( element => {
    document.body.appendChild(element);
  });
})

webpack.common.js:

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); 

module.exports = {
  entry: {
    main: './src/index.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    }, {
      test: /\.jpg$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 2048
        }
      }
    }, {
      test: /\.scss$/,
      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: ['style-loader', 'css-loader', 'postcss-loader']
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin()
  ],
  optimization: {
    splitChunks: {
      chunks: 'all',   //意思就是我要帮你去做代码分割了
      cacheGroups: {
        vendors: false,
        default: false
      }
    }
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].js'
  }
}

执行打包命令,此时控制台的network只加载了main.js:

再页面点击之后,才加载lodash.js文件:

上面这种做法的好处是能够让页面的加载速度更快,只加载该页面用到的js代码。

 

可以使用async函数来实现上面的效果,index.js:

async function getComponent() {
  const { default: _ } = await import(/* webpackChunkName: "lodash" */'lodash');
  const element = document.createElement('div');
  element.innerHTML = _.join(['z', 't'], '-');
  return element;
}

document.addEventListener('click', () => {
  getComponent().then( element => {
    document.body.appendChild(element);
  });
})


2、Chunk

Webpack打包过后生成了几个js文件,每个js文件我们都把它叫做一个Chunk。

 


六. 打包分析,Preloading, Prefetching

1、打包分析:当我们使用Webpack进行打包之后,我们可以借助打包分析的工具来对我们的打包文件进行一定的分析,然后看打包是否合理。

打包分析网址

上面网址中的教程:

  • 运行:npx webpack --profile --json > stats.json 会在根目录下生成一个stats.json,该文件就是对打包过程的一个描述。
  • 生成该文件以后,我们就可以借助一些工具来分析里面的内容了:进入上面的网址,点击首页的链接,就会进入一个页面,进入之后将stats.json文件上传上去就会帮我们进行打包分析了。

除了这个分析方法之外,还有很多别的方法,可以去webpack的文档中查看。

 


七.  CSS 文件的代码分割

  • index.js
import './style.css';
  • 在src目录下创建style.css文件,添加代码:
body {
  background-color: green;
}

执行打包后发现虽然dist目录下没有css文件,但是页面却又效果。这是因为webpack在做打包的时候会把Css文件直接打包到js里面。

 

1、希望实现Css文件单独打包进dist文件夹下面。

借助 MiniCssExtractPlugin 这个插件来进来css代码分割。

  • 安装: 
    npm install --save-dev mini-css-extract-plugin
  • webpack.common.js添加配置:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const {CleanWebpackPlugin} = require('clean-webpack-plugin'); 
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  entry: {
    main: './src/index.js'
  },
  module: {
    rules: [{
      test: /\.js$/,
      exclude: /node_modules/,
      loader: 'babel-loader'
    }, {
      test: /\.jpg$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name].[ext]',
          outputPath: 'images/',
          limit: 2048
        }
      }
    }, {
      test: /\.scss$/,
      use: [
        MiniCssExtractPlugin.loader,    //1
        {
          loader: 'css-loader',
          options: {
            importLoaders: 2
          }
        },
        'sass-loader',
        'postcss-loader'
      ]
    }, {
      test: /\.css$/,
      use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader']   //2
    }]
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: './src/index.html'
    }),
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({})
  ],
  optimization: {
    splitChunks: {
      chunks: 'all'
    }
  },
  output: {
    path: path.resolve(__dirname, '../dist'),
    filename: '[name].js'
  }
}

此时执行打包命令后发现dist目录下成功打包出了css文件。

 

2、做Css代码的压缩

const TerserJSPlugin = require('terser-webpack-plugin');
// 安装这两个插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');

module.exports = {
  // 配置压缩
  optimization: {
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值