一个合格的Webpack4配置工程师素养:第三部分

栏目: JavaScript · 发布时间: 7年前

内容简介:之前有提过webpack根据不同的环境我们会加载不同的配置。我们只需要提取出三部分。我们这里现在简单分层:正式项目最好创建一个config/webpack目录管理。下面是源代码。

之前有提过webpack根据不同的环境我们会加载不同的配置。我们只需要提取出三部分。

- base: 公共的部分
- dev: 开发环境部分
- prod: 生产环境部分
复制代码
npm i -D webpack-merge
复制代码

我们这里现在简单分层:正式项目最好创建一个config/webpack目录管理。

一个合格的Webpack4配置工程师素养:第三部分

下面是源代码。

"scripts": {
    "dev": "cross-env NODE_ENV=development npx webpack --progress --config webpack.dev.config.js",
    "build": "cross-env NODE_ENV=production npx webpack --progress --config webpack.prod.config.js"
 },
复制代码
// webapck.base.config.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: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
                loader: 'url-loader',
                options: {
                    // 文件大小小于limit参数,url-loader将会把文件转为DataUR
                    limit: 10000,
                    name: '[name]-[hash:5].[ext]',
                    output: 'fonts/',
                    // publicPath: '', 多用于CDN
                }
            },
            // 处理文件
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                use: [
                    // 转base64
                    {
                        loader: 'url-loader',
                        options: {
                            // 具体配置见插件官网
                            limit: 10000,
                            name: '[name]-[hash:5].[ext]',
                            outputPath: 'img/', // outputPath所设置的路径,是相对于 webpack 的输出目录。
                            // publicPath 选项则被许多webpack的插件用于在生产模式下更新内嵌到css、html文件内的 url , 如CDN地址
                        },
                    },
                    {
                        loader: 'image-webpack-loader',
                        options: {
                          mozjpeg: {
                            progressive: true,
                            quality: 65
                          },
                          // optipng.enabled: false will disable optipng
                          optipng: {
                            enabled: false,
                          },
                          pngquant: {
                            quality: '65-90',
                            speed: 4
                          },
                          gifsicle: {
                            interlaced: false,
                          },
                          // the webp option will enable WEBP
                          webp: {
                            quality: 75
                          }
                        }
                    }
                ]
            }
        ]
    },
    plugins: [
        // 打包模板
        new HtmlWebpackPlugin({
            inject: true,
            hash: true,
            cache: true,
            chunksSortMode: 'none',
            title: 'Webapck4-demo', // 可以由外面传入
            filename: 'index.html', // 默认index.html
            template: path.resolve(__dirname, 'index.html'),
            minify: {
                collapseWhitespace: true,
                removeComments: true,
                removeRedundantAttributes: true,
                removeScriptTypeAttributes: true,
                removeStyleLinkTypeAttributes: true
            }
        }),
        // 清理dist目录
        new CleanWebpackplugin(['dist'])
    ]
}

复制代码
// webpack.dev.config.js

const path = require('path')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.config.js')


module.exports = merge(baseWebpackConfig, {
    mode: 'development',
    output: {
        filename: 'bound.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            // 处理css/scss/sass
            {
                test: /\.(sc|sa|c)ss$/,
                use: [
                    {
                        loader: 'style-loader',
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: true
                        }
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            ident: 'postcss',
                            sourceMap: true,
                            plugins: (loader) => [
                                require('autoprefixer')({
                                    browsers: [
                                        'last 10 Chrome versions',
                                        'last 5 Firefox versions',
                                        'Safari >= 6',
                                        'ie > 8'
                                    ]
                                })
                            ]
                        }
                    },
                    {
                        loader: 'sass-loader',
                        options: {
                            sourceMap: true
                        }
                    }
                ]
            }
        ]
    }
})

复制代码
// webapck.prod.config.js

const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCSSAssertsPlugin = require('optimize-css-assets-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const merge = require('webpack-merge')
const baseWebpackConfig = require('./webpack.base.config.js')
const devMode = process.env.NODE_ENV !== 'production'

module.exports = merge(baseWebpackConfig, {
    mode: 'production',
    output: {
        filename: 'bound.[hash:5].js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            // 处理css/scss/sass
            {
                test: /\.(sc|sa|c)ss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    {
                        loader: 'css-loader'
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            ident: 'postcss',
                            plugins: (loader) => [
                                require('autoprefixer')({
                                    browsers: [
                                        'last 10 Chrome versions',
                                        'last 5 Firefox versions',
                                        'Safari >= 6',
                                        'ie > 8'
                                    ]
                                })
                            ]
                        }
                    },
                    {
                        loader: 'sass-loader'
                    }
                ]
            }
        ]
    },
    plugins: [
        // 提取CSS
        new MiniCssExtractPlugin({
            filename: devMode ? '[name].css' : '[name].[hash:5].css', // 设置输出的文件名
            chunkFilename: devMode ? '[id].css': '[id].[hash:5].css'
        })
    ],
    optimization: {
        minimizer: [
            // 压缩JS
            new TerserPlugin({
                cache: true,
                parallel: true,
                sourceMap: true,
                // 等等详细配置见官网
            }),
            // 压缩CSS
            new OptimizeCSSAssertsPlugin({})
        ]
    }
})

复制代码

webpack配置js使用sourceMap

在webpack4使用inline-source-map选项就可以启动错误的堆栈跟踪, 只用于开发环境

devtool: 'inline-source-map'
复制代码

监控文件变化自动编译

简单的方法就是启动watch模式: 如

"dev": "cross-env NODE_ENV=development npx webpack --progress --config webpack.dev.config.js --watch"
复制代码

webpack开启热更新和代理配置

很明显上面watch模式效率不高而且很不方便, 编译完还需要刷新页面, webpack可以开启热更新模式,大大加速开大效率。

npm i -D webpack-dev-server
复制代码

修改script脚本。

"dev": "cross-env NODE_ENV=development npx webpack-dev-server --progress --config webpack.dev.config.js"
复制代码

修改配置文件

const webpack = require('webpack')


plugins: [
    new webpack.NamedModulesPlugin(), // 更方便查看patch的依赖
    new webpack.HotModuleReplacementPlugin() // HMR
],
devServer: {
    clientLogLevel: 'warning', // 输出日志级别
    hot: true, // 启用热更新
    contentBase: path.resolve(__dirname, 'dist'), // 告诉服务器从哪里提供内容
    publicPath: '/', // 此路径下的打包文件可在浏览器下访问
    compress: true, // 启用gzip压缩
    // publicPath: './',
    disableHostCheck: true,
    host: '0.0.0.0',
    port: 9999,
    open: true, // 自动打开浏览器
    overlay: { // 出现错误或者警告时候是否覆盖页面线上错误信息
        warnings: true,
        errors: true
    },
    quiet: true,
    proxy: { // 设置代理
        '/dev': {
            target: 'http://dev.xxxx.com.cn',
            changeOrigin: true,
            pathRewrite: {
                '^/dev': ''
            }
            /**
             * 如果你的配置是
             * pathRewrite: {
                '^/dev': '/order/api'
                }
                即本地请求 /dev/getOrder   =>  实际上是  http://dev.xxxx.com.cn/order/api/getOrder
            */
        },
        '/test': {
            target: 'http://test.xxxx.com.cn',
            changeOrigin: true,
            pathRewrite: {
                '^/test': ''
            }
        },
        '/prod': {
            target: 'http://prod.xxxx.com.cn',
            changeOrigin: true,
            pathRewrite: {
                '^/prod': ''
            }
        }
    },
    watchOptions: { // 监控文件相关配置
        poll: true,
        ignored: /node_modules/, // 忽略监控的文件夹, 正则
        aggregateTimeout: 300, // 默认值, 当你连续改动时候, webpack可以设置构建延迟时间(防抖)
    }
}
复制代码

webpack启用babel转码

npm i -D  babel-loader @babel/core @babel/preset-env @babel/runtime @babel/plugin-transform-runtime
复制代码

修改配置文件

// 编译js
{
    test: /\.js$/,
    exclude: /(node_modules|bower_components)/,
    use: {
        loader: 'babel-loader?cacheDirectory', // 通过cacheDirectory选项开启支持缓存
        options: {
          presets: ['@babel/preset-env']
        }
    }
},
复制代码

增加.babelrc配置文件

// 仅供参考

{
    "presets": [
      [
        "@babel/preset-env"
      ]
    ],
    "plugins": [
      [
        "@babel/plugin-transform-runtime",
        {
          "corejs": false,
          "helpers": true,
          "regenerator": true,
          "useESModules": false,
          "absoluteRuntime": "@babel/runtime"
        }
      ]
    ]
  }

复制代码

webpack配置eslint校验

npm i -D eslint eslint-loader

// 校验规则
npm i -D babel-eslint standard
复制代码

修改webpack配置文件

// 编译js
  {
    test: /\.js$/,
    exclude: /(node_modules|bower_components)/,
    use: [
      {
        loader: 'babel-loader?cacheDirectory', // 通过cacheDirectory选项开启支持缓存
        options: {
          presets: ['@babel/preset-env']
        }
      },
      {
        loader: 'eslint-loader',
        options: {
          fix: true
        }
      }
    ]
  },
复制代码

增加.eslintrc.js文件

/*
 * ESLint的JSON文件是允许JavaScript注释的,但在gist里显示效果不好,所以我把.json文件后缀改为了.js
 */

/*
 * ESLint 配置文件优先级:
 * .eslintrc.js(输出一个配置对象)
 * .eslintrc.yaml
 * .eslintrc.yml
 * .eslintrc.json(ESLint的JSON文件允许JavaScript风格的注释)
 * .eslintrc(可以是JSON也可以是YAML)
 *  package.json(在package.json里创建一个eslintConfig属性,在那里定义你的配置)
 */

/*
 * 你可以通过在项目根目录创建一个.eslintignore文件告诉ESLint去忽略特定的文件和目录
 * .eslintignore文件是一个纯文本文件,其中的每一行都是一个glob模式表明哪些路径应该忽略检测
 */

module.exports = {
  //ESLint默认使用Espree作为其解析器
  //同时babel-eslint也是用得最多的解析器
  //parser解析代码时的参数
  "parser": "babel-eslint",
  "parserOptions": {
    //指定要使用的ECMAScript版本,默认值5
    "ecmaVersion": 6
    //设置为script(默认)或module(如果你的代码是ECMAScript模块)
    // "sourceType": "script",
    //这是个对象,表示你想使用的额外的语言特性,所有选项默认都是false
    // "ecmafeatures": {
    //   //允许在全局作用域下使用return语句
    //   "globalReturn": false,
    //   //启用全局strict模式(严格模式)
    //   "impliedStrict": false,
    //   //启用JSX
    //   "jsx": false,
    //   //启用对实验性的objectRest/spreadProperties的支持
    //   "experimentalObjectRestSpread": false
    // }
  },
  //指定环境,每个环境都有自己预定义的全局变量,可以同时指定多个环境,不矛盾
  "env": {
    //效果同配置项ecmaVersion一样
    "es6": true,
    "browser": true,
    "node": true,
    "commonjs": false,
    "mocha": true,
    "jquery": true,
    //如果你想使用来自某个插件的环境时,确保在plugins数组里指定插件名
    //格式为:插件名/环境名称(插件名不带前缀)
    // "react/node": true
  },

  //指定环境为我们提供了预置的全局变量
  //对于那些我们自定义的全局变量,可以用globals指定
  //设置每个变量等于true允许变量被重写,或false不允许被重写
  "globals": {
    "globalVar1": true,
    "globalVar2": false
  },

  //ESLint支持使用第三方插件
  //在使用插件之前,你必须使用npm安装它
  //全局安装的ESLint只能使用全局安装的插件
  //本地安装的ESLint不仅可以使用本地安装的插件还可以使用全局安装的插件
  //plugin与extend的区别:extend提供的是eslint现有规则的一系列预设
  //而plugin则提供了除预设之外的自定义规则,当你在eslint的规则里找不到合适的的时候
  //就可以借用插件来实现了
  "plugins": [
    // "eslint-plugin-airbnb",
    //插件名称可以省略eslint-plugin-前缀
    // "react"
  ],

  //具体规则配置
  //off或0--关闭规则
  //warn或1--开启规则,警告级别(不会导致程序退出)
  //error或2--开启规则,错误级别(当被触发的时候,程序会退出)
  "rules": {
    "eqeqeq": "warn",
    //你也可以使用对应的数字定义规则严重程度
    "curly": 2,
    //如果某条规则有额外的选项,你可以使用数组字面量指定它们
    //选项可以是字符串,也可以是对象
    "quotes": ["error", "double"],
    "one-var": ["error", {
      "var": "always",
      "let": "never",
      "const": "never"
    }],
    //配置插件提供的自定义规则的时候,格式为:不带前缀插件名/规则ID
    // "react/curly": "error"
  },

  //ESLint支持在配置文件添加共享设置
  //你可以添加settings对象到配置文件,它将提供给每一个将被执行的规则
  //如果你想添加的自定义规则而且使它们可以访问到相同的信息,这将会很有用,并且很容易配置
  "settings": {
    "sharedData": "Hello"
  },

  //Eslint检测配置文件步骤:
  //1.在要检测的文件同一目录里寻找.eslintrc.*和package.json
  //2.紧接着在父级目录里寻找,一直到文件系统的根目录
  //3.如果在前两步发现有root:true的配置,停止在父级目录中寻找.eslintrc
  //4.如果以上步骤都没有找到,则回退到用户主目录~/.eslintrc中自定义的默认配置
  "root": true,

  //extends属性值可以是一个字符串或字符串数组
  //数组中每个配置项继承它前面的配置
  //可选的配置项如下
  //1.字符串eslint:recommended,该配置项启用一系列核心规则,这些规则报告一些常见问题,即在(规则页面)中打勾的规则
  //2.一个可以输出配置对象的可共享配置包,如eslint-config-standard
    //可共享配置包是一个导出配置对象的简单的npm包,包名称以eslint-config-开头,使用前要安装
    //extends属性值可以省略包名的前缀eslint-config-
  //3.一个输出配置规则的插件包,如eslint-plugin-react
    //一些插件也可以输出一个或多个命名的配置
    //extends属性值为,plugin:包名/配置名称
  //4.一个指向配置文件的相对路径或绝对路径
  //5.字符串eslint:all,启用当前安装的ESLint中所有的核心规则
    //该配置不推荐在产品中使用,因为它随着ESLint版本进行更改。使用的话,请自己承担风险
  "extends": [
    "standard"
  ]
}

复制代码

增加.eslintignore文件

/dist/
/node_modules/
/*.js

复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First HTML and CSS

Head First HTML and CSS

Elisabeth Robson、Eric Freeman / O'Reilly Media / 2012-9-8 / USD 39.99

Tired of reading HTML books that only make sense after you're an expert? Then it's about time you picked up Head First HTML and really learned HTML. You want to learn HTML so you can finally create th......一起来看看 《Head First HTML and CSS》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具