5分钟打造简易高效的webpack常用配置

webpack给前端开发带来了毋庸置疑的改变,它把JS,图片,css都作为模块处理,同时具有开发便捷,自动化,兼容AMD写法等等诸多无须赘述的优点,更令人称道的是其插件社区非常强大,对于不同的业务需求和技术需求社区都有大量插件可供使用。

凡事都具有两面性,许多人说:前端开发再也不能只需新建HTML文件和JS文件就可以开始写代码了。webpack带来了更高级更规范的前端开发模式,由于其本身也在不断完善中,从1到2再到发布不久的webpack3,频繁的修改给新手带来了许多困惑。而且网络上各种教程鱼目混杂,经常出现别人的教程代码copy下来在自己的环境却跑不通的蛋疼问题。就拿 devtool 配置项来说,官方文档提供了多达7种的配置方法,连react核心团队成员Pete Hunt都在twitter上调侃:我分不清webpack的许多配置之间的区别。所以今天我们抛开那些琳琅满目的插件和令人烦躁的配置项,笔者和大家一起5分钟从零搭建一个简易高效的webpack开发环境。

首先我们明确一下需求:

  1. 打包调试
  2. 提取公共代码
  3. 压缩
  4. 热替换

1.打包调试

第一步,我们在目标文件夹下安装webpack(假设已有 package.json )

npm i webpack@ -g
cnpm i webpack@ --save-dev 

(这里推荐大家安装稳定的2.x版本)

项目结构如图:

我们将编写的js代码和样式文件放置在 app 文件夹内(正常项目开发需要 js 文件和 less文件更规范的组织文件结构,此处仅为演示方便)。

第二步,我们在目标文件夹下新建 webpack.config.js

module.exports = {
  entry:{
    main:__dirname + '/app/main.js',
  },
  output:{
    path:__dirname + '/public',
    filename:'[name].[id].js',//此格式写法后续会提到为什么
    publicPath:'/public/'
  }
}

我们已经完成了webpack最基础的部分:添加了文件的输入和输出。入口是 app 文件夹内的 main.js 文件,出口为 public 文件夹。接下来我们来处理各种文件的解析,就是大名鼎鼎的 loader 的舞台了。假设我们使用 es6 和 less 开发,那么我们需要:

npm i babel-loader babel-core babel-preset-es2015 babel-preset-stage-0 --save-dev

npm i less less-loader css-loader style-loader --save-dev

接下来我们只需要在 modules 字段下把这些 loader 加进去:

module.exports = {
  devtool:'cheap-module-eval-source-map',//多种选择,选择最适合自己的
  entry:{
    main:__dirname + '/app/main.js',
  },
  output:{
    path:__dirname + '/public',
    filename:'[name].[id].js',
    publicPath:'/public/'
  },
  module:{
    loaders:[
      {
        test:/\.js$/, //解析文件类型
        exclude:/node_modules/, //排除node_modules文件
        loader:'babel-loader', //使用哪种loader解析
        query:{
          presets:['es2015','stage-0']//loader的配置项,解析es6
        }
      },
      {
        test:/\.less$/,
        exclude:/node_modules/,
        loader:'style-loader!css-loader!less-loader'//顺序为从右向左
      }
    ]
  },
}

大功告成!

如果你在全局安装有webpack的话,可以在终端敲入webpack并回车,几秒钟后, main.js 文件已经在 public 打包出来了!

之后我们在 index.html 中引入 main.0.js 文件,再打开 index.html 就可以看到效果了。

以上步骤,我们已经实现了文件的打包调试,但是现在有个问题摆在我们面前:第三方库代码和业务代码打包到了同一个文件 main.0.js 内,每次更新代码都要更新整个文件。那么接下来我们对代码进行拆分。

2.提取公共代码

引入 CommonsChunkPlugin 插件,在 webpack.config.js 添加如下内容:

module.exports = {
  devtool:'cheap-module-eval-source-map',
  entry:{
    main:__dirname + '/app/main.js',
    vendor:'moment'
  },
  output:{
    path:__dirname + '/public',
    filename:'[name].[id].js',
    publicPath:'/public/'
  },
  module:{
    loaders:[
      {
        test:/\.js$/,
        exclude:/node_modules/,
        loader:'babel-loader',
        query:{
          presets:['es2015','stage-0']
        }
      },
      {
        test:/\.less$/,
        exclude:/node_modules/,
        loader:'style-loader!css-loader!less-loader'
      }
    ]
  },
  plugins:[
      new webpack.optimize.CommonsChunkPlugin({
        names:['vendor','manifest']
     })
   ]
}

我们看到向插件的构造函数传入了两个参数 vendor 和 manifest ,以及我们在 entry 也加入了新的入口 moment 。 moment 是常用的时间处理的第三方库,我们可以通过 npm i moment --save-dev 进行安装。而 entry 处的 vendor 将成为 output 字段 filename 中 [name] 的值,也就是说将打包出 main.x.js 和 vendor.x.js 两个文件, main.x.js 文件将保存我们的业务代码, vendor.x.js 将保存 moment 的代码,这样我们将公共代码和业务代码进行了初步分离。

在新添加的 CommonmChunkPlugin 插件中,我们添加了 manifest 值,这是为什么呢?如果你不添加这个值,你在打包时会发现, main.x.js 有更新, vendor.x.js 还是有更新,并未真正实现"分离"。官方文档对此的解释是:

The issue here is that on every build, webpack generates some webpack runtime code, which helps webpack do it's job. When there is a single bundle, the runtime code resides in it. But when multiple bundles are generated, the runtime code is extracted into the common module, here the vendor file.

大致的意思就是说,webpack每次编译时运行的代码会影响到 hash 值的变化,当只有一个打包文件时这部分代码会塞进去,当有多个打包文件时,这部分代码会进入公共的 vendor 。所以解决办法是使用 manifest 字段把这部分代码从 vendor 中作为一个公共模块抽出来,从而不会影响 vendor 。

将以上的配置写入 webpack.config.js ,运行webpack命令,我们发现业务代码和公共库代码成功分离,改写 main.1.js 文件的内容,再次打包,发现 vendor 文件并没有变化,成功!

当我们再进行打包时,发现又会多出了新的 main.x.js 等文件,打包三次就会出现三个 main.x.js 文件,此时该怎么办呢?我们可以使用 clean-webpack-plugin 插件:

npm i clean-webpack-plugin --save-dev

然后在 webpack.config.js 中引入:

var CleanWebpackPlugin = require('clean-webpack-plugin');
  new CleanWebpackPlugin(
      ['public/main.*.js','public/manifest.*.js'],//要删除的文件目录匹配
      {
        root:__dirname,
        verbose:true,
        dry:false
      }
    ),

这样我们每次在打包新的代码时,旧文件就会删除,不会再出现同一份文件存在多份的情况。

3.压缩

在webpack中,图片,css,js等等其他资源皆可压缩,本文仅以压缩js为例。

安装插件:

npm i uglifyjs-webpack-plugin --save-dev

在 webpack.config.js 中引入:

var UglifyJsPlugin = require('uglifyjs-webpack-plugin');
new UglifyJsPlugin({
  beautify:true,
  exclude:['/node_modules/'],
  compress:{
    warnings:false
  },
  output:{
    comments:false
  }
})

我们指定了压缩的方法,排除了不需要压缩的 node_modules 部分,同时我们去除了 comments 部分( comments 为@license等注释,是可观的压缩空间)。再次在终端输入打包命令,可见js打包后的体积有令人满意的减小。

4.热替换

webpack总是绕不开热替换的话题。热替换的功能配置和原理是一大话题,三天三夜也说不完,也并非本文重点,本文只提供简易高效的配置方法。

热替换存在两种使用方式, cli 和 node 。 cli 方式无需添加新的热替换插件,且无需在入口处添加 webpack-dev-server 等入口,故本文采用 cli 使用方式。

在 webpack.config.js 中添加 devServer 字段,加入如下代码:

devServer:{
  inline:true,
  hot:true
},

保存后运行 webpack-dev-server --inline --hot --progress ,再修改下 main.less 文件的样式,会发现浏览器并没有刷新,但页面已经发生了变化,我们的热替换功能也成功加入了!

tips:

在实际项目打包时,可以将 filename 字段的值换为 [name].[chunkhash].js ,其中 [chunkhash] 为webpack每次打包后给每个模块的标识值,这个值每次打包后都会更换。为什么在此处我们使用 [id] 呢,因为 chunkhash 与热替换存在冲突,终端会有报错,那么使用 id 可以算作一个解决方案。这就引申出另一话题,我们可以使用两套webpack配置分别用于生产环境和开发环境,通过webpack指定config来进行打包。例如我们在开发环境使用 id ,在生产环境去掉热替换并使用 hash 的方式。而且,一些压缩插件也没必要在开发环境过度使用,两套配置能让webpack发挥最大的威力。

另外, chunkhash 和 hash 有区别, chunkhash 顾名思义是模块的标识,而 hash 是webpack每次编译的标识值,不同的资源如js和css存在 chunkhash 解耦的问题,此处不进行过多讨论。

5.运行

我们知道,每次打包后,都会有新的 main.x.js 文件生成,其hash值每次打包后都会发生变化,难道我们的 index.html 文件需要每次打包后都手动修改 main.x.js 的路径吗?还好社区提供了 html-webpack-plugin 插件,可以在已有html模板的条件下自动为我们生成带有最新代码的html文件:

npm i html-webpack-plugin --save-dev

在 webpack.config.js 中引入:

var HtmlWebpackPlugin = require('html-webpack-plugin');
new HtmlWebpackPlugin({
  title:'demo',
  template:'index.html'
}),

在终端运行打包命令,我们看到 public 文件夹下生成了新的 index.html 文件:

以后我们再进行调试时,以本文为例,则需要打开 localhost:8080/public/index.html ,因为每次webpack的 HtmlWebpackPlugin 都会把新的js文件加入到这个html文件内。在开发全部完成后,我们可以将js路径写死,添加到原有的 index.html 文件中。

以下是我们 webpack.config.js 全部的配置;

var webpack = require('webpack');
var CleanWebpackPlugin = require('clean-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var UglifyJsPlugin = require('uglifyjs-webpack-plugin');

module.exports = {
  devtool:'cheap-module-eval-source-map',
  entry:{
    main:__dirname + '/app/main.js',
    vendor:'moment'
  },
  output:{
    path:__dirname + '/public',
    filename:'[name].[id].js',
    publicPath:'/public/'
  },
  devServer:{
    inline:true,
    hot:true
  },
  module:{
    loaders:[
      {
        test:/\.js$/,
        exclude:/node_modules/,
        loader:'babel-loader',
        query:{
          presets:['es2015','stage-0']
        }
      },
      {
        test:/\.less$/,
        exclude:/node_modules/,
        loader:'style-loader!css-loader!less-loader'
      }
    ]
  },
  plugins:[
    new CleanWebpackPlugin(
      ['public/main.*.js','public/manifest.*.js'],
      {
        root:__dirname,
        verbose:true,
        dry:false
      }
    ),
    new webpack.optimize.CommonsChunkPlugin({
      names:['vendor','manifest']
    }),
    new HtmlWebpackPlugin({
      title:'demo',
      template:'index.html'
    }),
    new UglifyJsPlugin({
      beautify:true,
      exclude:['/node_modules/'],
      compress:{
        warnings:false
      },
      output:{
        comments:false
      }
    })
  ]
}

整个项目,我们在 app 文件下的 main.js 内写业务代码, main.less 写样式,在 public/index.html 下使用热替换进行调试,打包后的压缩文件在 public 文件夹下,并且对业务代码,第三方代码进行了清晰地区分。

使用这份webpack配置,我们实现了:

  1. 工程的打包调试
  2. 公共代码提取,提高开发效率
  3. 资源压缩
  4. 热替换

这份配置麻雀虽小,五脏俱全。本文还有许多不完善之处,比如一些插件的使用方法,原理没有与大家讲清楚,但webpack实在太庞大了,一个插件的使用方法和原理都可以写上千字的文章了,学习不可浅尝辄止,但也不能太钻牛角尖,与大家共勉~

(0)

相关推荐

  • 深入理解Webpack 中路径的配置

    前言 Webpack2 中有很多涉及路径参数配置,若不知其所以然,很容易混淆出错.本文尽可能的汇集了 Webpack2 中涉及路径的配置,力争深入浅出. context context 是 webpack 编译时的基础目录,入口起点(entry)会相对于此目录查找. 默认值为当前目录,webpack设置 context 默认值代码 可以本地下载: this.set("context", process.cwd()); process.cwd()即webpack运行所在的目录(等同pac

  • webpack入门+react环境配置

    小结放在前:这篇文章主要是为下一篇的react提前铺好路,webpack是一个前端资源模块化管理和打包工具,说白了就是方便我们管理自己的常用的一些代码,比如你开发中用到sass以及jade同时用到es6,开发时你不可能改动某个地方就挨个命令去转换在到浏览器去看效果,那样效率是非常低的.所以webpack帮我们省去了那些多余的步骤 webpack 基本安装 开始前还是万万不能缺少的安装: npm install webpack -g 安装完接着是建个文件夹新建一个package.json依赖管理文

  • 详解webpack es6 to es5支持配置

    1. 安装webpack npm install webpack --save-dev 2. 安装babel  实现 ES6 到 ES5 npm install --save-dev babel-core babel-preset-es2015 3.安装 babel-loader npm install --save-dev babel-loader webpack.config.js完整配置 module.exports = { entry: './src/js/app.js', output

  • webpack配置文件和常用配置项介绍

    1.安装webpack 1.全局安装webpack:npm install webpack -g 或者转化了cnpm则将npm改为cnpm进行安装 2.进行初始化建立package.json文件记录插件,命令行:npm init 3.webpack安装到项目并将写入package.json的devDependencies中, 命令行:npm install webpack --save-dev. 2.webpack配置文件介绍 1.webpack需要配置文件webpack.config.js,手

  • webpack常用配置项配置文件介绍

    一.webpack基础 1.在项目中生成package.json:在项目根目录中输入npm init,根据提示输入相应信息.(也可以不生成package.json文件,但是package.json是很有用的,所有建议生成) 2.安装webpaack a.在全局中安装webpack:npm install webpack -g b.将webpack安装到项目并将webpack写入package.json的devDependencies中:进入项目根目录,然后在命令行中输入npm install w

  • webpack配置的最佳实践分享

    本文主要介绍了关于webpack配置的最佳实践,本文分享的实践具有以下的优势: 使用happypack提升打包速度. 使用MD5 hash可以生成文件版本,进行版本控制 在非单页面的系统中支持多个入口的配置 模板中可以利用htmlplugin输出一些配置性的信息 支持devserver,支持本地json数据的mock 一.webpack最佳实践中的需求 1.热加载 2.语法校验 3.js打包 4.模板打包 二.解决方案 1.webpack.config.json var path = requi

  • 详解webpack 多入口配置

    同事套搭建vue项目,个人推荐了VUE官网的vue-cil的方式,http://cn.vuejs.org/guide/application.html 顺着官网的操作,我们可以本地测试起我们的项目 npm run dev,首先我们要理解webpack打包主要是针对js,查看下面生成的配置,首页是index.html,模版用的index.html,入口文件用的mian.js //file build/webpack.base.conf.js //entry 配置 module.exports =

  • Vue + Webpack + Vue-loader学习教程之相关配置篇

    前言 之前已经介绍过了Vue + Webpack + Vue-loader的相关功能介绍,大家可以点击这篇文章了解详情.下面就来看看相关配置篇,感兴趣的可以参考学习. 使用预处理器 在 Webpack 中,所有的预处理器需要和一个相应的加载器一同使用.vue-loader 允许你用其它的 Webpack 加载器去处理 Vue 组件一部分代码.它会根据 lang 属性自动用适当的加载器去处理. CSS 例如,我们编译用 SASS 编译 <style> 标签: npm install sass-l

  • vue-cli的webpack模板项目配置文件分析

    由于最近在vue-cli生成的webpack模板项目的基础上写一个小东西,开发过程中需要改动到build和config里面一些相关的配置,所以刚好趁此机会将所有配置文件看一遍,理一理思路,也便于以后修改配置的时候不会"太折腾". 一.文件结构 本文主要分析开发(dev)和构建(build)两个过程涉及到的文件,故下面文件结构仅列出相应的内容. ├─build │ ├─build.js │ ├─check-versions.js │ ├─dev-client.js │ ├─dev-ser

  • 详解vue2.0脚手架的webpack 配置文件分析

    前言 作为 Vue 的使用者我们对于 vue-cli 都很熟悉,但是对它的 webpack 配置我们可能关注甚少,今天我们为大家带来 vue-cli#2.0 的 webpack 配置分析 vue-cli 的简介.安装我们不在这里赘述,对它还不熟悉的同学可以直接访问 vue-cli 查看 目录结构 . ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-server

随机推荐