webpack实践小结

本文将对webpack2在实际项目的使用进行总结

Posted by lijiahao on October 15, 2017

webpack作为一个模块打包器(module bundler),webpack视HTML,JS,CSS,图片等文件都是一种资源,每个资源文件都是一个module文件,webpack就是根据每个module文件之间的依赖关系将所有的module打包(bundle)起来。本文将介绍自己平时开发过程对webpack的一些实践。

ps.本人webpack的实践是配合Vue框架进行开发,故以下介绍有少部分内容是基于Vue框架进行说明,不过原理也是适用于其他框架的。

webpack基本配置组成

webpack的配置在实际开发中一般以独立的文件存在,每个配置文件都是JavaScript 文件导出的一个对象,公共的配置部分为webpack.base.conf.js,再根据开发(dev)和生产(prod)分webpack.dev.conf.jswebpack.prod.conf.js。一个成熟的webpack.base.conf.js里导出的对象包含:

  • entry:入口文件
  • output:bundle后输出文件,包括输出文件的文件名、路径等
  • resolve:模块解析,一般是是设置模块的解析路径、文件别名等
  • module:解析不同类型模块的loader,如url-loader、eslint-loader等
  • plugins:定制webpack构建过程的插件或者自定义插件,如LoaderOptionsPlugin等

使用resolve.alias别名替代完整路径

webpack把一切模块视为资源,因此在每个模块中,我们可以使用通过导入模块使用其他模块,webpack支持CommonJs的require()和ES6的import等常见的模块导入方式,下面是导入一个公共文件夹(_image)图片的示例:

var img = require('../../_image/webpack.png')

正常情况下需要使用相对路径导入,也就是你需要一级一级目录的往上找出当前模块的路径,如果文件路径比较深,那么require的路径中就会出现很多../,代码就因此显得不优雅,因为这个_image文件夹是放在项目最外层的公共文件夹,如果以项目最外层开始索引,那么require下的路径就只是_image/webpack.png,省去许多../,我们可以通过webpack的resolve.alias给路径设置别名:

var path = require('path')
module.exports = {
  ...
  resolve: {
    alias: { // 设置路径别名
      '_image': path.resolve(__dirname, './_image')
      'styles': path.resolve(__dirname, './src/_styles')
    }
  }
  ...
}

在任意位置引用_image文件夹时如下:

var img = require('_image/webpack.png')

如果是在CSS中使用路径别名,需要在别名前加上~,以下是在stylusimport公共变量文件variables.styl

<style scoped lang="stylus">
	/* 设置styles的别名后要在别名前加上~ */
  	@import "~styles/variables";
	.demo { color: _grey; }
</style>

使用resolve.extensions添加扩展名

引用其他文件时需要注明该文件的类型,如注册一个全局modal组件需要注明文件扩展名:

import Vue
Vue.component('modal', require('src/_components/ui/modal/modal.vue'));

在webpack配置resolve.extensions将常见的文件名加上后,加不需要每次都加上文件扩展名了:

webpack.base.conf.js

module.exports = {
  ...
  extensions: ['.js', '.vue', '.json']
  ...
}

代码分割

代码分割(Code Splitting)是webpack的强大功能之一,代码分割可以将第三方库代码(vendor)和业务代码分开打包,在使用到对应的逻辑的时候才引入相应的代码,从而使得页面加载的js文件体积大大降低,提升页面性能,关于webpack的代码分割具体可以参考Webpack 大法之 Code Splitting。代码分割的关键点在于找到代码的分割点,在Vue框架开发的SPA中,我们可以将每一个路由视为一个分割点,在进入到该路由的时候才会加载该页面所需的js文件。具体的做法是在每个路由上使用resolve来动态加载所需JS:

// src/_router/index.js
import Router from 'vue-router';
export default new Router({
  mode: 'history',
  base: '/',
  routes: [
      {
        path: '/page',
        name: 'page_name',
        component: function (resolve) { // 通过异步加载
          require(['../page/page.vue'], resolve)
        }
      }
  ]
});

LoaderOptionsPlugin设置全局变量

默认情况下,webpack不会将任何module暴露给全局,如果需要使用全局模块(如jQuery或全局CSS变量),需要通过plugins进行实现,例如有全局的stylus变量模块variables.styl,通过webpack内置的LoaderOptionsPlugin可以将这个模块暴露给全局:

plugins: [
    new webpack.LoaderOptionsPlugin({
      options: {
        stylus: {
          import: [
            path.resolve(__dirname, './src/_styles/variables.styl')
          ]
        }
      }
    })
  ]

这样,在每个组件中使用到全局CSS变量时,不需再使用@import "~styles/variables";即可直接使用变量。

(完)


原创不易,如果觉得这篇文章对你有帮助,不如赏杯咖啡吧
微信
支付宝