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
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须在文章页面给出原文连接,否则保留追究法律责任的权利。
  • 相关阅读:
    Begin Example with Override Encoded SOAP XML Serialization
    State Machine Terminology
    How to: Specify an Alternate Element Name for an XML Stream
    How to: Publish Metadata for a WCF Service.(What is the Metadata Exchange Endpoint purpose.)
    Beginning Guide With Controlling XML Serialization Using Attributes(XmlSerializaiton of Array)
    Workflow 4.0 Hosting Extensions
    What can we do in the CacheMetaData Method of Activity
    How and Why to use the System.servicemodel.MessageParameterAttribute in WCF
    How to: Begin Sample with Serialization and Deserialization an Object
    A Test WCF Service without anything of config.
  • 原文地址:https://www.cnblogs.com/cirry/p/webpack-config-js.html
Copyright © 2011-2022 走看看