zoukankan      html  css  js  c++  java
  • webpack开发环境基本配置

    2021年6月2号更新
    官方提供webpack配置描述信息:https://www.webpackjs.com/configuration/
    我的项目地址:https://github.com/cirry/webpack-template
    项目根据最新webpack版本,不断优化代码,复制即用,github上有没有注释的webpack配置文件,webpack.config.no-comment.js。

    目录结构如下图

    webpack.config.js

    下图是我的简单配置,供日常开发使用:

    const {resolve} = require('path')
    const HtmlWebpackPlugin = require('html-webpack-plugin')
    const MiniCssExtractPlugin = require('mini-css-extract-plugin')
    const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin')
    // optimize-css-assets-webpack-plugin
    const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
    const TerserPlugin = require('terser-webpack-plugin')
    
    // 设置nodejs的环境变量
    // process.env.NODE_ENV = "development"
    // process.env.NODE_ENV = "production"
    const isProduction = process.env.NODE_ENV === 'production';
    
    // css兼容性配置
    const CommonCSSLoader = [
        {
            loader: "postcss-loader",
            options: {
                postcssOptions: {
                    ident: 'postcss',
                    //打包后有兼容性样式代码,只处理css文件,不处理less文件
                    plugins: [
                        require('postcss-preset-env')
                    ],
                }
            }
        },
    ]
    
    module.exports = {
        mode: "development",
        // 下面这个是开启全部的js兼容性方式,开启的话需删除js中的按需加载
        // entry: ["@babel/polyfill", "./src/index.js"],
        // 第一个入口是js,第二个是html,这样再修改js和html都可以做到热更新
        entry: ["./src/index.js", "./src/index.html"],
        output: {
            filename: "js/[name].[contenthash:10].js",
            // __dirname, nodejs的变量,代表当前文件的目录绝对路径
            // path: resolve(__dirname, 'build'),
            publicPath: "/",
            chunkFilename: "js/[name].[contenthash:10]_chunk.js"
        },
        module: {
            rules: [
                {
                    test: /.css$/, use: [
                        isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
                        'css-loader',
                        ...CommonCSSLoader,
                    ]
                },
                {
                    test: /.less$/, use: [
                        isProduction ? MiniCssExtractPlugin.loader : 'style-loader',
                        'css-loader',
                        ...CommonCSSLoader,
                        'less-loader',
                    ]
                },
                // 仅能处理css中的引入的图片
                {
                    test: /.(jpg|png|gif|jpe?g)$/, loader: "url-loader", options: {
                        // 小于8kb的图片会被处理为base64
                        limit: 8 * 1024,
                        name: '[name].[hash:10].[ext]',
                        outputPath: 'image'
                    }
                },
                // 处理html文件中的img图片(负责引入img,从而能被url-loader进行处理)
                {
                    test: /.html$/, loader: "html-loader", options: {
                        // 问题: 因为url-loader默认使用es6模块化解析,而html-loader引入图片使用的是common.js[解析时会出问题]
                        esModule: false
                    }
                },
                //npm install -D babel-loader @babel/core @babel/preset-env webpack
                // 只处理基本的js语法,全部js兼容性处理:@babel/polyfill
                {
                    test: /.m?js$/,
                    exclude: /node_modules/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            presets: [
                                ['@babel/preset-env',
                                    {
                                        // 指定兼容性做到哪个版本的浏览器,使用默认,配置方式跟browserList差不多
                                        "targets": {
                                            "ie": 7,
                                            "edge": "17",
                                            "firefox": "60",
                                            "chrome": "67",
                                            "safari": "11.1",
                                        },
                                        // 按需加载
                                        useBuiltIns: "usage",
                                        // 指定corejs版本
                                        corejs: {
                                            version: 3
                                        }
                                    }
                                ]
                            ],
                            cacheDirectory: true
                        }
                    }
                },
                {
                    test: /.(woff2?|eot|ttf|otf)(?.*)?$/,
                    loader: 'url-loader',
                    options: {
                        limit: 1024 * 8,
                        name: "[name].[hash:10].[ext]",
                        outputPath: "fonts"
                    }
                },
                {
                    test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/,
                    loader: 'url-loader',
                    options: {
                        limit: 1024 * 8 * 5,
                        name: "[name].[hash:10].[ext]",
                        outputPath: "media"
                    }
                },
            ],
        },
        plugins: [
            // 在内存中创建index.html文件,并自动引入js和css文件,html模板为template路径的页面
            new HtmlWebpackPlugin({
                template: "./src/index.html",
                // 压缩html代码
                minify: {
                    collapseWhitespace: true,
                    removeComments: true,
                }
            }),
            // 提取css代码为单独的文件,默认会被压缩在js文件中
            new MiniCssExtractPlugin({
                filename: 'css/[name].[contenthash:10].css',
            }),
            //压缩css代码
            new OptimizeCssAssetsWebpackPlugin()
        ],
        optimization: {
            // 配置生产环境的压缩方案,压缩js和css
            minimizer: [
                // For webpack@5 you can use the `...` syntax to extend existing minimizers (i.e. `terser-webpack-plugin`), uncomment the next line
                // `...`,
                new CssMinimizerPlugin(),
                new TerserPlugin()
            ],
            // 可以将node_modules中的代码单独打包成一个chunk输出
            splitChunks: {
                chunks: "all",
                //下面所有的属性都是默认值,不用写
                // minSize: 30 * 1024, // 小于30kb不分割
                // maxSize: 0, // 最大没有限制
                // minChunks: 1, // 要提取的chunks最少被引用1次
                // maxAsyncRequests: 5, // 按需加载时,并行加载文件的最大数量
                // maxInitialRequests: 3, //入口js文件,最大并行请求数量
                // automaticNameDelimiter: "~", // 名称连接符
                // name: true, // 可以使用命名规则
                // cacheGroups: { // 分割chunk的组
                //     // node_modules文件中的文件会被打包到vendors组的chunk中 --> vendors~xxx.ks,连接符号是波浪线是因为前面的automaticNameDelimiter属性
                //     // 满足上面的公共规则,如大小超过30kb,至少被引用一次
                //     vendors: {
                //         test: /[\/]node_modeuls[\/]/,
                //         // 优先级
                //         priority: -10
                //     },
                //     default:{
                //         // 要提取的chunk最少被引用两次
                //         minChunks: 2,
                //         priority: -20,
                //         // 如果当前要打包的模块,和之前已经被提取的模块是同一个,就会被复用,而不是重新打包模块
                //         reuseExistingChunk: true
                //     }
                // }
            },
            // 将当前模块的记录其他模块的hash单独打包为一个文件,叫runtime文件
            // 解决:修改a文件导致b文件的contenthash变化
            runtimeChunk: {
                name: (entrypoint) => `runtime~${entrypoint.name}`,
            },
        },
        // 打包在内存中, 自动编译,自动打开浏览器,自动刷新
        devServer: {
            contentBase: resolve(__dirname, 'dist'), // 运行的目录,不是源代码,而是构建后的目录
            compress: true,
            host: 'localhost',
            port: 3000,
            open: true,
            hot: true,
            // 没有跨域问题,忽略proxy配置
            proxy: {
                // 一旦devServer(3000)服务器接收到/api/xxx的请求,就会把请求转发到另外一个服务器(5000)上
                '/api': {
                    target: 'http://localhost:5000',
                    // 发送请求时,请求路径重写: 将/api/xxx -->/xxx
                    pathRewrite: {
                        '^/api': ''
                    }
                }
            }
        },
        // 热更新需要属性
        target: 'web',
        // 开发生产坏境报错需要
        devtool: 'source-map',
        // 排除jquery不打包
        externals: {
            // 拒绝jquery被打包
            jquery: 'jQuery',
        }
    }
    
    

    package.json 需要装的包:

    {
      "name": "webpack-template",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo "Error: no test specified" && exit 1",
        "dev": "cross-env NODE_ENV=development webpack serve",
        "build": "cross-env NODE_ENV=production webpack"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@babel/core": "^7.14.3",
        "@babel/preset-env": "^7.14.4",
        "babel-loader": "^8.2.2",
        "core-js": "^3.13.1",
        "cross-env": "^7.0.3",
        "css-loader": "^5.2.6",
        "css-minimizer-webpack-plugin": "^3.0.0",
        "file-loader": "^6.2.0",
        "html-loader": "^2.1.2",
        "html-webpack-plugin": "^5.3.1",
        "less": "^4.1.1",
        "less-loader": "^9.0.0",
        "mini-css-extract-plugin": "^1.6.0",
        "optimize-css-assets-webpack-plugin": "^6.0.0",
        "postcss-loader": "^5.3.0",
        "postcss-preset-env": "^6.7.0",
        "style-loader": "^2.0.0",
        "terser-webpack-plugin": "^5.1.3",
        "url-loader": "^4.1.1",
        "webpack": "^5.38.1",
        "webpack-cli": "^4.7.0",
        "webpack-dev-server": "^3.11.2"
      },
      "browserslist": {
        "development": [
          "last 1 chrome version",
          "last 1 firefox version",
          "last 1 safari version"
        ],
        "production": [
          ">0.2%",
          "not dead",
          "not op_mini all"
        ]
      },
      "dependencies": {
        "@babel/polyfill": "^7.12.1",
        "jquery": "^3.6.0"
      }
    }
    
    

    详细说明配置含义

    基础属性

    1. 在webpack5中,入口entry 默认值为:'./src',出口output默认值为:'./dist',可以不用配置。
    2. mode属性:可以设置为“development”或“production”,我已通过cross-env设置node环境。
    3. devtool属性:开发生产的时候代码报错,用来定位错误代码位置。
    4. externals属性:排除外来第三方包,不参与打包,减少打包代码量和加载速度,用第三方引入。

    hash含义

    为什么要引入hash?
    首先webpack中有三种hash模式,分别为:hash/fullhash,chunkhash,contenthash,参考output中filename: "js/[name].[contenthash:10].js"的使用方式。

    • 从不同包中引入的相同名称的图片,可以通过打包hash还来区分他们。
    • 缓存问题。
      • 比如我们加载一个页面需要有a.js和a.css文件,当文件被缓存的时候,我们不加hash值,修改a.css的文件内容,重新打包部署,浏览器不会去请求服务器拿新页面而是使用缓存中的页面。因为浏览器会认为文件名称没有变化,内容没有变更,不需要去获取新的文件。
      • 这里我们给文件名称加上第一种hash值,js/[name].[hash:10].js, css/[name].[hash:10].css,这一种hash值是每次webpack打包都会生成的整体的hash值,这会让每个文件的hash值都是相同的。当我们修改css的文件内容然后重新打包的时候,会重新生成hash值,刷新浏览器,会去重新请求js和css文件,而我们只改了一个css文件,却也请求了两个文件,因为两个文件的名称都变了。
      • 第二种hash值,js/[name].[chunkhash:10].js, css/[name].[chunkhash:10].css,这里因为我们就一个chunk, 目录结构比较简单,所以会跟第一种情况。当项目复杂,有不同的chunk的时候,就会有差别。
      • 第三种hash值,js/[name].[contenthash:10].js, css/[name].[contenthash:10].css,这里使用的是根据文件内容生成hash值,当我们只修改css文件后重新打包,会发现,js文件还是之前的名称,而css文件名称已经发生了变化。刷新浏览器会去重新请求css文件,而js文件是走的缓存。

    module用法

    module中主要是对文件的处理操作,根据rules的匹配规则对不同的文件加载不同的loader处理方式。
    例如对less文件,我们依次使用:['style-loader','css-loader','less-loader'],数组中的三个文件,在文件为.less文件的时候,会从右向左依次被处理。

    • 先被less-loader处理,将less转化为css
    • 再被css-loader处理,将css转化为commonjs
    • 再被style-loader处理,将样式通过<style>加载到html页面中

    其中,css文件和js文件都有兼容性问题,js有例如promise,匿名函数,解构,es6新特性。css有例如3d样式,flex等等。
    处理js文件的兼容性问题是使用了babel-loader,处理css文件兼容性问题是使用了postcss-loader。

    插件作用

    webpack.config.js中共用到了三个插件。

    1. HtmlWebpackPlugin 插件
      此插件,在开发过程中,将打包号的代码编译在内存中,并选择./src/index.html作为模版内容,并挂在上需要引入的css文件和js文件。
    2. MiniCssExtractPlugin 插件
      webpack默认会将css代码压缩在js文件中,通过此插件可以将css文件提取成单独的文件。
    3. OptimizeCssAssetsWebpackPlugin 插件
      第二个插件会将css文件提取出来,但并没有压缩css代码,通过此插件可压缩css代码。

    optimization作用

    1. minimizer
      配置生产环境的代码压缩方法,CssMinimizerPlugin 压缩css代码,TerserPlugin 压缩js代码。
    2. splitChunks
      可以将node_modules中的代码单独打包成一个chunk输出,上图中被注释掉的代码都是webpack默认的参数配置。
    3. runtimeChunk
      将当前模块的记录其他模块的hash单独打包为一个文件,叫runtime文件。
      比如,我们在a.js中引入了b.js,当b.js的文件内容修改了之后,重新打包,会重新打包a.js文件和b.js文件。我们用runtimeChunk把a.js和b.js的hash值抽离出来单独管理,当b.js的hash改变了之后,a.js的内容并没有改变就不需要重新打包a.js。

    externals 使用方式

    externals: {
            jquery: 'jQuery',
            Konva: 'Konva'
        }
    

    其中小写的"jquery"是你在项目中引用的包名,import $ from 'jquery'中的 'jquery'。
    大写的"jQuery"是包暴露出来的对象名,比如jquery包中,最后暴露出来的名称是 export default jQuery

    有疑问或者问题,请留言,本人常在回复比较及时。
    作者:Cirry
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    OpenGL红宝书例3.1 -- glBufferSubData使用
    JNI调用问题(部分机型崩溃)
    文件编码转换工具
    vs2013安装visual assist和viemu之后提示功能等无效解决
    cocos2d-lua SDK接入
    OpenGL中shader读取实现
    CURL C++网络延时或者最低网速下载设置
    Spring框架
    软件安装方式
    Web前端常见问题
  • 原文地址:https://www.cnblogs.com/cirry/p/webpack-config-js.html
Copyright © 2011-2022 走看看