博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
一个合格的Webpack4配置工程师素养:第三部分
阅读量:6679 次
发布时间:2019-06-25

本文共 14842 字,大约阅读时间需要 49 分钟。

前两篇

webpack配置分层

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

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

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

下面是源代码。

"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.jsconst 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.jsconst 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.jsconst 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复制代码

webpack配置resolve模块解析

配置alias方便路径的检索效率。 配置文件默认扩展名,import时候自动匹配。

resolve: {    extensions: ['.js', '.vue', '.json'],    alias: {      '@': path.resolve(__dirname, 'src/')    }},复制代码

webpack配置外部扩展externals

externals选项可以提供排除打包某些依赖到boundle的方法.例如我们想通过CDN引入jQuery而不是把jQuery打包到boudle。

这里以jQuery为例:

修改配置文件

// 配置外部依赖不会打包到boudleexternals: {    jquery: 'jQuery'},复制代码

在模板文件引入CDN

// index.html    
<%= htmlWebpackPlugin.options.title %>
复制代码

在index.js使用jquery

import $ from 'jquery'// 测试外部扩展配置$(function () {  $('.logo').click(function () {    console.log('click')  })})复制代码

webpack打包报表分析以及优化

npm i -D webpack-bundle-analyzer复制代码

我单独配置了一个命令进行打包分析:

"build:report": "cross-env NODE_ENV=production npx webpack --progress --config webpack.analysis.config.js"复制代码

当然你其实完全可以通过传参数配置集成到prod那个配置文件如:

"build:report": "npm run build --report"复制代码

然后在prod配置环境中如果参数判断:

// 伪代码if (config.build.bundleAnalyzerReport) {  var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin  webpackConfig.plugins.push(new BundleAnalyzerPlugin())}复制代码

这里给出我的方案

const merge = require('webpack-merge')const prodWebpackConfig = require('./webpack.prod.config.js')const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPluginmodule.exports = merge(prodWebpackConfig, {  plugins: [    new BundleAnalyzerPlugin() // 打包分析  ]})复制代码

仓库地址

有用的话点个star, 有问题欢迎提issues。

转载地址:http://jagxo.baihongyu.com/

你可能感兴趣的文章
angularjs笔记(二)
查看>>
SQL Server数据库多种方式查找重复记录
查看>>
Target runtime Apache Tomcat v6.0 is not defined.错误解决方法
查看>>
为什么我们要研究中断?【转】
查看>>
tcpdump wireshark 实用过滤表达式(针对ip、协议、端口、长度和内容) 实例介绍...
查看>>
C#.net调用axis2webService
查看>>
NOIP2010乌龟棋[DP 多维状态]
查看>>
Linux 系统中用户切换(su user与 su - user 的区别)
查看>>
微信订阅号消息回复测试
查看>>
数据库 Proc编程二
查看>>
zabbix-agent 自动注册
查看>>
基于3D Vision眼镜的OSG立体显示 【转】
查看>>
java.lang.AbstractStringBuilder.enlargeBuffer
查看>>
HTML5新增与结构有关的元素
查看>>
C# 复制和克隆认识浅谈
查看>>
Python和Flask真强大:不能错过的15篇技术热文(转载)
查看>>
【LeetCode】Swap Nodes in Pairs 链表指针的应用
查看>>
Swift,Objective-C语言性能对照測试
查看>>
[Node] Using dotenv to config env variables
查看>>
Easyui的numberbox无法输入以0开头的数字编号(转载)
查看>>