653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash

什么是CDN?

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash


购买CDN服务器

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash


第三方库的CDN服务器

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash


认识shimming【了解】

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash


Shimming预支全局变量

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash


MiniCssExtractPlugin

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash


目录结构

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash


index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
  <div id="root"></div>

  <!-- 【开发环境下,不需要cdn】 -->
  <!-- ejs中的if判断 -->
  <% if (process.env.NODE_ENV === 'production') { %> 
  <script src="https://unpkg.com/dayjs@1.8.21/dayjs.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/lodash@4.17.21/lodash.min.js"></script>
  <% } %> 
</body>
</html>

main.js

import _ from 'lodash';
import dayjs from 'dayjs';

import "./request";
import "./style.css";

console.log("Hello Main");
console.log(_.join(["Hello", "Main"]));
console.log(dayjs(), "Main");

webpack.common.js

const resolveApp = require("./paths");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const VueLoaderPlugin = require("vue-loader/lib/plugin");
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');

const { merge } = require("webpack-merge");

const prodConfig = require("./webpack.prod");
const devConfig = require("./webpack.dev");

const commonConfig = (isProduction) => {
  return {
    // 【hash:多入口进行打包的时候,如果每一个地方发生变化,另一个文件也发生变化,就用hash】
    entry: {
      main: "./src/main.js",
      index: "./src/index.js"
      // main: { import: "./src/main.js", dependOn: "shared" },
      // index: { import: "./src/index.js", dependOn: "shared" },
      // lodash: "lodash",
      // dayjs: "dayjs"
      // shared: ["lodash", "dayjs"]
    },
    output: {
      path: resolveApp("./build"),
      filename: "js/[name].bundle.js",
      chunkFilename: "js/[name].[hash:6].chunk.js",
      publicPath: ""
    },
    resolve: {
      extensions: [".wasm", ".mjs", ".js", ".json", ".jsx", ".ts", ".vue"],
      alias: {
        "@": resolveApp("./src"),
        pages: resolveApp("./src/pages"),
      },
    },
    optimization: {
      // 对代码进行压缩相关的操作
      minimizer: [
        new TerserPlugin({
          extractComments: false,
        }),
      ],
      // natural: 使用自然数(不推荐),
      // named: 使用包所在目录作为name(在开发环境推荐)
      // deterministic: 生成id, 针对相同文件生成的id是不变
      // chunkIds: "deterministic",
      splitChunks: {
        // async异步导入
        // initial同步导入
        // all 异步/同步导入
        chunks: "all",
        // 最小尺寸: 如果拆分出来一个, 那么拆分出来的这个包的大小最小为minSize
        minSize: 20000,
        // 将大于maxSize的包, 拆分成不小于minSize的包
        maxSize: 20000,
        // minChunks表示引入的包, 至少被导入了几次
        minChunks: 1,
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            filename: "js/[id]_vendors.js",
            // name: "vendor-chunks.js",
            priority: -10
          },
          // bar: {
          //   test: /bar_/,
          //   filename: "[id]_bar.js"
          // }
          default: {
            minChunks: 2,
            filename: "common_[id].js",
            priority: -20
          }
        }
      },
      // true/multiple
      // single
      // object: name
      runtimeChunk: {
        name: function(entrypoint) {
          return `why-${entrypoint.name}`
        }
      }
    },
    module: {
      rules: [
        {
          test: /\.jsx?$/i,
          use: "babel-loader",
        },
        {
          test: /\.vue$/i,
          use: "vue-loader",
        },
        {
          test: /\.css/i,
          // style-lodader -> development,开发环境才需要 【生产环境用 MiniCssExtractPlugin.loader。】
          use: [
            isProduction ? MiniCssExtractPlugin.loader: "style-loader", 
            "css-loader"],
        },
      ],
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: "./index.html",
      }),
      new VueLoaderPlugin(),
      // 当在代码中遇到某一个变量找不到时, 我们会通过ProvidePlugin, 自动导入对应的库
      // new webpack.ProvidePlugin({
      //   axios: "axios",
      //   get: ["axios", "get"]
      // })
    ],
  };
}

module.exports = function(env) {
  const isProduction = env.production;
  process.env.NODE_ENV = isProduction ? "production" : "development";

  const config = isProduction ? prodConfig : devConfig;
  const mergeConfig = merge(commonConfig(isProduction), config);

  return mergeConfig;
};

webpack.prod.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const isProduction = true;

module.exports = {
  mode: "production",
  externals: {
    // window._
    lodash: "_", // value写lodash暴露出来的全局对象
    // window.dayjs
    dayjs: "dayjs"
  },
  plugins: [
    // 生产环境
    new CleanWebpackPlugin({}),
    new MiniCssExtractPlugin({
      filename: "css/[name].[hash:8].css"
    })
  ]
}

webpack.dev.js

const resolveApp = require('./paths');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');

const isProduction = false;

console.log("加载devConfig配置文件");

module.exports = {
  mode: "development",
  devServer: {
    hot: true,
    hotOnly: true,
    compress: true,
    contentBase: resolveApp("./why"),
    watchContentBase: true,
    proxy: {
      "/why": {
        target: "http://localhost:8888",
        pathRewrite: {
          "^/why": ""
        },
        secure: false,
        changeOrigin: true
      }
    },
    historyApiFallback: {
      rewrites: [
        {from: /abc/, to: "/index.html"}
      ]
    }
  },
  plugins: [
    // 开发环境
    new ReactRefreshWebpackPlugin(),
  ]
}

Hash、ContentHash、ChunkHash

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash


目录结构

653 webpack中使用CDN、shimming,Hash、ContentHash、ChunkHash


main.js

import "./style.css";

console.log("indexaaaaaccccc");

webpack.common.js

const resolveApp = require("./paths");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const VueLoaderPlugin = require("../../19_webpack的DLL引入/config/node_modules/vue-loader/lib/plugin");
const TerserPlugin = require("terser-webpack-plugin");
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const webpack = require('webpack');

const { merge } = require("webpack-merge");

const prodConfig = require("./webpack.prod");
const devConfig = require("./webpack.dev");

const commonConfig = (isProduction) => {
  return {
    entry: {
      main: "./src/main.js",
      index: "./src/index.js"
      // main: { import: "./src/main.js", dependOn: "shared" },
      // index: { import: "./src/index.js", dependOn: "shared" },
      // lodash: "lodash",
      // dayjs: "dayjs"
      // shared: ["lodash", "dayjs"]
    },
    output: {
      path: resolveApp("./build"),
      filename: "js/[name].[chunkhash:6].bundle.js",
      chunkFilename: "js/[name].[contenthash:6].chunk.js",
      publicPath: ""
    },
    resolve: {
      extensions: [".wasm", ".mjs", ".js", ".json", ".jsx", ".ts", ".vue"],
      alias: {
        "@": resolveApp("./src"),
        pages: resolveApp("./src/pages"),
      },
    },
    optimization: {
      // 对代码进行压缩相关的操作
      minimizer: [
        new TerserPlugin({
          extractComments: false,
        }),
      ],
      // natural: 使用自然数(不推荐),
      // named: 使用包所在目录作为name(在开发环境推荐)
      // deterministic: 生成id, 针对相同文件生成的id是不变
      // chunkIds: "deterministic",
      splitChunks: {
        // async异步导入
        // initial同步导入
        // all 异步/同步导入
        chunks: "all",
        // 最小尺寸: 如果拆分出来一个, 那么拆分出来的这个包的大小最小为minSize
        minSize: 20000,
        // 将大于maxSize的包, 拆分成不小于minSize的包
        maxSize: 20000,
        // minChunks表示引入的包, 至少被导入了几次
        minChunks: 1,
        cacheGroups: {
          vendor: {
            test: /[\\/]node_modules[\\/]/,
            filename: "js/[id]_vendors.js",
            // name: "vendor-chunks.js",
            priority: -10
          },
          // bar: {
          //   test: /bar_/,
          //   filename: "[id]_bar.js"
          // }
          default: {
            minChunks: 2,
            filename: "common_[id].js",
            priority: -20
          }
        }
      },
      // true/multiple
      // single
      // object: name
      // runtimeChunk: {
      //   name: function(entrypoint) {
      //     return `why-${entrypoint.name}`
      //   }
      // }
    },
    module: {
      rules: [
        {
          test: /\.jsx?$/i,
          use: "babel-loader",
        },
        {
          test: /\.vue$/i,
          use: "vue-loader",
        },
        {
          test: /\.css/i,
          // style-lodader -> development
          use: [
            isProduction ? MiniCssExtractPlugin.loader: "style-loader", 
            "css-loader"],
        },
      ],
    },
    plugins: [
      new HtmlWebpackPlugin({
        template: "./index.html",
      }),
      new VueLoaderPlugin(),
      // 当在代码中遇到某一个变量找不到时, 我们会通过ProvidePlugin, 自动导入对应的库
      // new webpack.ProvidePlugin({
      //   axios: "axios",
      //   get: ["axios", "get"]
      // })
    ],
  };
}

module.exports = function(env) {
  const isProduction = env.production;
  process.env.NODE_ENV = isProduction ? "production" : "development";

  const config = isProduction ? prodConfig : devConfig;
  const mergeConfig = merge(commonConfig(isProduction), config);

  return mergeConfig;
};

webpack.dev.js

const resolveApp = require('./paths');
const ReactRefreshWebpackPlugin = require('../../19_webpack的DLL引入/config/node_modules/@pmmmwh/react-refresh-webpack-plugin');

const isProduction = false;

console.log("加载devConfig配置文件");

module.exports = {
  mode: "development",
  devServer: {
    hot: true,
    hotOnly: true,
    compress: true,
    contentBase: resolveApp("./why"),
    watchContentBase: true,
    proxy: {
      "/why": {
        target: "http://localhost:8888",
        pathRewrite: {
          "^/why": ""
        },
        secure: false,
        changeOrigin: true
      }
    },
    historyApiFallback: {
      rewrites: [
        {from: /abc/, to: "/index.html"}
      ]
    }
  },
  plugins: [
    // 开发环境
    new ReactRefreshWebpackPlugin(),
  ]
}

webpack.prod.js

const { CleanWebpackPlugin } = require('../../19_webpack的DLL引入/config/node_modules/clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const isProduction = true;

module.exports = {
  mode: "production",
  externals: {
    lodash: "_",
    dayjs: "dayjs"
  },
  plugins: [
    // 生成环境
    new CleanWebpackPlugin({}),
    new MiniCssExtractPlugin({
      filename: "css/[name].[contenthash:6].css"
    })
  ]
}

上一篇:ckeditor5上传配置 ckeditor5图片上传功能 富文本编辑器图片上传功能


下一篇:webpack高级概念,webpack与浏览器的缓存(系列九)