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 相关文章推荐
jQuery实现隔行背景色变色
Nov 24 Javascript
纯javascript响应式树形菜单效果
Nov 10 Javascript
AngularJs动态加载模块和依赖注入详解
Jan 11 Javascript
深入解析JavaScript中函数的Currying柯里化
Mar 19 Javascript
javascript实现的左右无缝滚动效果
Sep 19 Javascript
Vue 中的compile操作方法
Feb 26 Javascript
Vue项目部署的实现(阿里云+Nginx代理+PM2)
Mar 26 Javascript
JS实现可切换图片的幻灯切换效果示例
May 24 Javascript
Vue实现星级评价效果实例详解
Dec 30 Javascript
详解JS深拷贝与浅拷贝
Aug 04 Javascript
Openlayers绘制地图标注
Sep 28 Javascript
解决vue页面刷新,数据丢失的问题
Nov 24 Vue.js
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
PHP的FTP学习(四)
2006/10/09 PHP
php编程实现获取excel文档内容的代码实例
2011/06/28 PHP
ThinkPHP的截取字符串函数无法显示省略号的解决方法
2014/06/25 PHP
PHP过滤黑名单关键字的方法
2014/12/01 PHP
Javascript 学习书 推荐
2009/06/13 Javascript
五段实用的js高级技巧
2011/12/20 Javascript
javascript通过className来获取元素的简单示例代码
2014/01/10 Javascript
js操作IE浏览器弹出浏览文件夹可以返回目录路径
2014/07/14 Javascript
同一个网页中实现多个JavaScript特效的方法
2015/02/02 Javascript
jQuery实现简单二级下拉菜单
2015/04/12 Javascript
JS正则表达式学习之贪婪和非贪婪模式实例总结
2016/12/26 Javascript
利用VUE框架,实现列表分页功能示例代码
2017/01/12 Javascript
JSON与js对象序列化实例详解
2017/03/16 Javascript
详解Vue.js Mixins 混入使用
2017/09/15 Javascript
vue使用xe-utils函数库的具体方法
2018/03/06 Javascript
详解vue2.0监听属性的使用心得及搭配计算属性的使用
2018/07/18 Javascript
vue 引用自定义ttf、otf、在线字体的方法
2019/05/09 Javascript
微信小程序 云开发模糊查询实现解析
2019/09/02 Javascript
vue中解决chrome浏览器自动播放音频和MP3语音打包到线上的实现方法
2020/10/09 Javascript
[02:35]DOTA2超级联赛专访XB 难忘一年九冠称王
2013/06/20 DOTA
Python判断列表是否已排序的各种方法及其性能分析
2016/06/20 Python
Windows下python3.6.4安装教程
2018/07/31 Python
python游戏开发的五个案例分享
2020/03/09 Python
Python实现Keras搭建神经网络训练分类模型教程
2020/06/12 Python
AmazeUI折叠式卡片布局,整合内容列表、表格组件实现
2020/08/20 HTML / CSS
奥斯汀独木舟和皮划艇:Austin Canoe & Kayak
2018/05/22 全球购物
static全局变量与普通的全局变量有什么区别
2014/05/27 面试题
史上最全面的Java面试题汇总!
2015/02/03 面试题
大学毕业的自我鉴定
2013/10/08 职场文书
幼儿园教师工作制度
2014/01/22 职场文书
岗位职责怎么写
2014/03/14 职场文书
《长征》教学反思
2014/04/27 职场文书
2015毕业生实习工作总结
2014/12/12 职场文书
力克胡哲观后感
2015/06/10 职场文书
创业计划书之婴幼儿游泳馆
2019/09/11 职场文书
从零开始在Centos7上部署SpringBoot项目
2022/04/07 Servers