webpack开发环境和生产环境的深入理解


Posted in Javascript onNovember 08, 2018

以前自己写一小项目时,webpack的配置基本就是一套配置,没有考虑生产环境和开发环境的区分,最近在做一个复杂的商城项目接触到了webpack的高级配置,经过两天的研究,写出了一份目前来说比叫满意的配置,在这里分享一下。

如何区分开发环境和生产环境?

众所周知,webpack时基于node.js平台运行的,要区分开发环境和生产环境还要存,node入手。我们启动webpack时,都需要输入一些命令,npm run 、yarn start之类的,所以我们就从命令行入手,告诉webpack,当前是什么环境。

package.json

{
  "name": "webpac-demo",
  "version": "1.0.0",
  "description": "webpack练习",
  "main": "index.js",
  "scripts": {
    //配置开发环境参数。注意:真实开发中 package.json 文件中不能有注释
    "dev": "webpack --env=development",
    //配置生产环境参数
    "dist": "webpack --env=production",
    "start": "webpack-dev-server --env=development"
  },
  "dependencies": {
    "font-awesome": "^4.7.0",
    "react": "^16.2.0",
    "react-dom": "^16.2.0"
  },
  "devDependencies":{
  ...
  }
}

这样配置,当我们在命令行输入 npm run dev 和 npm run dist 时,就会附带一些参数到命令行中,有了参数,我们该如何拿到呢?那就要用到 node 的一个命令行参数解析引擎了。

minimist

minimist轻量级的命令行参数解析引擎

// test.js
var args = require('minimist')(process.argv.slice(2));
console.log(args.hello);

$ node test.js --env=production
// production
$ node test.js --env=development
// development
$ node test.js --env
// true 注意:不是空字符串而是true

minimist会把参数解析成一个JSON对象:{key:value},有了这个JSON对象,我们就可以知道,当前的命令是要执行开发打包,还是生产打包了。

// webpack.config.js

const webpack = require('webpack');
//当前项目的绝对路劲
const path = require('path');

// 命令行参数解析引擎
const argv = require('minimist')(process.argv.slice(2));

let env = null;

switch (argv.env) {
  case 'production':
    //生产环境配置文件名 
    env = 'webpack.config.prod';
    break;
  default:
    //开发环境配置文件名 
    env = 'webpack.config.dev';

}

console.log(`当前是 ${argv.env} 打包`);

// 这时候,我们就可以加载相应的wabpack配置了。
module.exports = require( path.resolve( '加载的配置文件路劲',env ) );

webpack开发环境配置和生产环境配置

开发环境配置

在开发环境下,我们首先考虑的是方便开发,方便代码调试,不需要考虑代码合并和css样式分离这些。

这里主要说三个 :1.css模块化;2.模块热替换功能;3.source-map(代码映射)

// 开发环境打包配置

const path = require('path');
const webpack = require('webpack');
const base = require('./webpack.config.base')
const dfPath = require('./path')
// webpack配置合并工具
const merge =require('webpack-merge')


const RS = (...arg)=>path.resolve( __dirname , ...arg )

// 合并方式配置
let strategyMerge = merge.strategy({
  entry: 'prepend'
});

let config = {
  entry: {
    app: path.resolve(dfPath.root,'src/app.js')
  },

  output: {
    path: dfPath.dist,
    filename: '[name].bundle.js',
    publicPath: '/',
    chunkFilename: '[name].sepChunk.js'
  },
  module:{
    rules: [
      {
        test: /\.js$/,
        use:['babel-loader'],
        exclude: [
          dfPath.node_modules
        ]
      },
      {
        test:/\.css$/,
        use:[
          'style-loader',
          {
            loader:'css-loader',
            options:{
              // css模块化,方便多人开发
              module:true,
              // 定义模块化css后的类名(默认为hash值,可读性差)path:路劲; name:文件名; local:本地定义的className
              localIdentName: '[path][name]__[local]--[hash:base64:5]'
            },
          }
        ],
        // 排除的文件,遇到这些文件不会用当前 loader 处理,也就不会模块化
        exclude:[
          RS('./src/common'),         
          RS('node_modules')
        ]
      },
      {
        test:/\.css$/,
        use:['style-loader','css-loader'],
        include:[
          RS('./src/common'),         
          RS('node_modules')
        ]
        
      },      
      
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        use: ['url-loader?limit=8192'],
      }
    ]
  },
  plugins:[
    // 模块热替换功能
    new webpack.HotModuleReplacementPlugin()
  ],
  
  // 代码映射,方便报错时,找到对应的源代码
  devtool: 'cheap-module-eval-source-map',

  devServer:{
    // 服务器打包后,输出的资源路劲
    publicPath:'/',
    open:true
  }
};

// 导出合并后的webpack配置
module.exports = strategyMerge( base , config );

生产环境配置

相比开发环境,生产环境打包是要最后发布到服务器部署的代码,我们需要尽量保持代码简洁,加载性能最优,不需要调试辅助工具。

我们从这几个方面优化 :1.公共模块拆分,单独打包;2. css文件分离,单独打包输出;3.代码压缩;

// 生产环境配置
const webpack = require('webpack');
const base = require('./webpack.config.base')
const path = require('path');
const dfPath = require('./path');
const merge = require('webpack-merge');

// 压缩工具
const ClosureCompilerPlugin = require('webpack-closure-compiler');
// css单独打包插件
const extractTextWebpackPlugin = require('extract-text-webpack-plugin');

const extractCSS = new extractTextWebpackPlugin('assets/css/[name]_[contenthash:6].css');

// weback合并配置
let strategyMerge = merge.strategy({
  entry: 'replace',
  output: 'replace',
  module:{
    rules: 'replace'
  }
});

let config ={

  entry: {
    // 公共模块拆分,这些代码会单独打包,一般我们会把引用的框架文件拆分出来,方便浏览器缓存,节省资源。
    vender:['react'],
    app: path.resolve(dfPath.root,'src/app.js')
  },
  
  output: {
    path: dfPath.dist,
    filename: 'assets/js/[name]_[chunkhash].bundle.js',
    publicPath: '/',
    chunkFilename: 'assets/js/[name].sepChunk.js',
    hashDigestLength: 6
  },

  module:{
    rules: [
      {
        test: /\.js$/,
        use:['babel-loader'],
        exclude: [
          dfPath.node_modules
        ]
      },
      /* 开启 css单独打包 和 css模块化的配置 */ 
      {
        test: /\.css$/,
        use: extractCSS.extract({
          use: [
            {
              loader: 'css-loader',
              options:{
                modules: true
              }              
            }
          ]
        })
      },     

      {
        test: /\.(png|jpg|jpeg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options:{
              limit:8192,
              name: '[name]_[hash].[ext]',
              outputPath: 'assets/img/'
            }
          }
        ],
      },
      
      {
        test: /\.(mp4|ogg|svg|ico)$/,
        use: [
          {
            loader: 'file-loader',
            options:{
              name: '[name]_[hash].[ext]',
              outputPath: 'assets/media/'
            }
          }
        ]
      },
      {
        test: /\.(woff|woff2)(\?v=\d+\.\d+\.\d+)?$/,
        use: [

          {
            loader: 'url-loader',
            options:{
              limit:10000,
              name: '[name]_[hash].[ext]',
              outputPath: 'assets/font/',
              mimetype: 'application/font-woff'
            }
          }
        ]
      },
      {
        test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
        use: [
          {
            loader: 'url-loader',
            options:{
              limit:10000,
              name: '[name]_[hash].[ext]',
              outputPath: 'assets/font/',
              mimetype: 'application/octet-stream'
            }
          }
        ]
      },
      {
        test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
        use: [
          {
            loader: 'file-loader',
            options:{
              name: '[name]_[hash].[ext]',
              outputPath: 'assets/font/',
            }
          }
        ]
      },
      {
        test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
        use: [
          {
            loader: 'url-loader',
            options:{
              limit:10000,
              name: '[name]_[hash].[ext]',
              outputPath: 'assets/font/',
              mimetype: 'image/svg+xml'
            }
          }
        ]
      },

    ]
  },

  plugins:[
    extractCSS,
    
    // 设置 process.env(生产环境) 环境变量的快捷方式。
    new webpack.EnvironmentPlugin({
      NODE_ENV: 'production'
    })    
    ,new ClosureCompilerPlugin()
  ],

  devtool: 'source-map'
};

module.exports = strategyMerge(base,config);

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Javascript 相关文章推荐
用正则xmlHttp实现的偷(转)
Jan 22 Javascript
小议javascript 设计模式 推荐
Oct 28 Javascript
js实现的简洁网页滑动tab菜单效果代码
Aug 24 Javascript
JavaScript模拟鼠标右键菜单效果
Dec 08 Javascript
微信小程序 常见问题总结(4058,40013)及解决办法
Jan 11 Javascript
javascript 中关于array的常用方法详解
May 05 Javascript
vue2.0的虚拟DOM渲染思路分析
Aug 09 Javascript
微信小程序车牌号码模拟键盘输入功能的实现代码
Nov 11 Javascript
原生js实现可兼容PC和移动端的拖动滑块功能详解【测试可用】
Aug 15 Javascript
js贪心算法 钱币找零问题代码实例
Sep 11 Javascript
js单线程的本质 Event Loop解析
Oct 29 Javascript
深入分析JavaScript 事件循环(Event Loop)
Jun 19 Javascript
webpack 开发和生产并行设置的方法
Nov 08 #Javascript
JS动画实现回调地狱promise的实例代码详解
Nov 08 #Javascript
深入解析ES6中的promise
Nov 08 #Javascript
vue中promise的使用及异步请求数据的方法
Nov 08 #Javascript
node使用Mongoose类库实现简单的增删改查
Nov 08 #Javascript
webpack4+express+mongodb+vue实现增删改查的示例
Nov 08 #Javascript
Echarts之悬浮框中的数据排序问题
Nov 08 #Javascript
You might like
常用表单验证类,有了这个,一般的验证就都齐了。
2006/12/06 PHP
php中防止伪造跨站请求的小招式
2011/09/02 PHP
php读取文件内容的方法汇总
2015/01/24 PHP
php数组使用规则分析
2015/02/27 PHP
PHP验证信用卡卡号是否正确函数
2015/05/27 PHP
Thinkphp实现自动验证和自动完成
2015/12/19 PHP
利用PHP绘图函数实现简单验证码功能的方法
2016/10/18 PHP
PHP 实现页面静态化的几种方法
2017/07/23 PHP
EasySlider 基于jQuery功能强大简单易用的滑动门插件
2010/06/11 Javascript
js封装的textarea操作方法集合(兼容很好)
2010/11/16 Javascript
JS版的date函数(和PHP的date函数一样)
2014/05/12 Javascript
jquery+php实现搜索框自动提示
2014/11/28 Javascript
jQuery的end()方法使用详解
2015/07/15 Javascript
angularjs 表单密码验证自定义指令实现代码
2016/10/27 Javascript
JS创建对象的写法示例
2016/11/04 Javascript
js选项卡的制作方法
2017/01/23 Javascript
Angular将填入表单的数据渲染到表格的方法
2017/09/22 Javascript
浅析Node.js非对称加密方法
2018/01/29 Javascript
在vue项目中,使用axios跨域处理
2018/03/07 Javascript
详解在Vue.js编写更好的v-for循环的6种技巧
2020/04/14 Javascript
vue-i18n实现中英文切换的方法
2020/07/06 Javascript
python列表操作使用示例分享
2014/02/21 Python
使用apidocJs快速生成在线文档的实例讲解
2018/02/07 Python
Python Requests库基本用法示例
2018/08/20 Python
python实现在函数中修改变量值的方法
2019/07/16 Python
PYTHON绘制雷达图代码实例
2019/10/15 Python
Restful_framework视图组件代码实例解析
2020/11/17 Python
python mongo 向数据中的数组类型新增数据操作
2020/12/05 Python
Python 中如何使用 virtualenv 管理虚拟环境
2021/01/21 Python
英国殿堂级有机护肤品牌:Rodial
2017/04/17 全球购物
为女性购买传统的印度服装和婚纱:Kalkifashion
2019/07/22 全球购物
英国高级健康和美容产品零售商:Life and Looks
2019/08/01 全球购物
单位作风建设剖析材料
2014/10/11 职场文书
2015年勤工助学工作总结
2015/04/29 职场文书
学校食堂食品安全承诺书
2015/04/29 职场文书
selenium.webdriver中add_argument方法常用参数表
2021/04/08 Python