分享web开发知识

注册/登录|最近发布|今日推荐

主页 IT知识网页技术软件开发前端开发代码编程运营维护技术分享教程案例
当前位置:首页 > 软件开发

webpack 使用总结

发布时间:2023-09-06 01:20责任编辑:胡小海关键词:webpack

什么是 webpack

Webpack 是德国开发者 Tobias Koppers 开发的一个强力的模块打包器。 所谓包(bundle)就是一个 JavaScript 文件,它把一堆资源(assets)合并在一起,以便它们可以在同一个文件请求中发回给客户端。 包中可以包含 JavaScript、CSS 样式、HTML 以及很多其它类型的文件。

为什么要使用 webpack

  • 与 react 一类模块化开发的框架搭配着用比较好。
  • 属于配置型的构建工具,容易上手,160 行代码可大致实现 gulp 400 行才能实现的功能。
  • webpack 使用内存来对构建内容进行缓存,构建过程会比较快。

webpack 的特点

能够实现多种不同的前端模块系统
前端页面越来越复杂、代码量变大,我们需要使用一些模块系统来组织代码、把代码分割成不同的模块来使用。
目前前端模块系统主要分为以下几个标准:

  • Script标签形式
  • CommonJS
  • AMD和一些变种实现
  • CMD
  • ES6模块

以上方式有各自的优缺点,这里不做赘述。
webpack 作为一个智能解析器,可以处理几乎任何第三方的库,无论他们的模块形式是 commonjs,amd 还是普通的 js 文件,甚至加载依赖的时候可以动态表达式:

import React, { PropTypes } from ‘react‘
require(‘es6-promise‘).polyfill()
require("./templates/" + name + ".jade")
var $ = require(‘jQuery‘)

分块打包
资源请求是个老生常谈的优化问题,有两个极端的方向来处理资源:

  • 将所有文件都打包在一个请求里
  • 每个模块都发起一个请求

webpack 打包前端资源(模块)时能够实现代码分割,按需加载,如在单页面应用里,将每个 page 的资源单独打包,按页面加载。这种方式被称为 code splitting(具体实现方式查看:https://webpack.github.io/docs/code-splitting.html。

处理所有资源
目前模块系统只能处理 javascript,而我们还有很多其他静态资源需要处理,比如:

  • 预编译的 js 文件(coffeescript 或 jsx 或 es6 -> javascript)
  • css 文件 (less -> css -> autoprefixer)
  • 图片 (压缩、转 base64)
  • 模板 (jade、各种template)
  • 等等

配置 webpack 后,这些都很容易处理。

webpack 与 、requirejs 等工具的区别

gulp、grunt 是自动化任务构建工具。
webpack 是模块化解决方案。

gulp 是通过一系列插件将原本复杂繁琐的任务(Task)自动化,并不能将你的 css 等非 js 资源模块化,它与 webpack 之间有一定的功能重合,比如打包、压缩混淆、图片转 base64 等等。但它们的目的跟要解决的问题是不一样的。

webpack 本质上是类似 browserify、seajs 、requirejs 的JS模块化的方案。其中 seajs / require 是一种类型,browserify / webpack 是另一种类型。

seajs / require : 是一种在线”编译” 模块的方案,相当于在页面上加载一个 CMD/AMD 解释器。这样浏览器就认识了 define、exports、module 这些东西。也就实现了模块化。

browserify / webpack : 是一种预编译模块的方案,相比于上面 ,这个方案更加智能。这里以webpack为例。首先,它是预编译的,不需要在浏览器中加载解释器。另外,你在本地直接写JS,不管是 AMD / CMD / ES6 风格的模块化,它都能认识,并且编译成浏览器认识的JS。

webpack 的配置

首先看一个简单的 webpack 配置图。
webpack.config.js:

Webpack的配置主要为了这几个项目:
devtool
devtool 属性可以配置调试代码的方式,有多种调试方式。devtool 一般只在开发时使用,生产环境下应将值设为 false。常用的值为以下两个:

  • eval
    可以设断点调试,不显示列信息,每个js模块代码用eval()执行,并且在生成的每个模块代码尾部加上注释,不会生成.map文件。
  • source-map
    可以设断点调试,不显示列信息,生成相应的.Map文件,并在合并后的代码尾部加上注释//# sourceMappingURL=**.js.map ,可以看到模块代码并没有被eval()包裹,此种模式并没有将调试信息放入D打包后的代码中,保持了打包后代码的简洁性.

其他还有eval-source-map、cheap-source-map、cheap-module-source-map、cheap-module-eval-source-map、hidden-source-map,也可以自己组合,如cheap-module-eval-source-map。

// webpack.config.js
module.exports = {
devtool: ‘cheap-module-eval-source-map‘
};

据说cheap-module-eval-source-map绝大多数情况下都会是最好的选择,这也是下版本 webpack 的默认选项。

具体使用参考官网devtool部分

entry 和 output
entry 用来定义入口文件,可以是个字符串或数组或者对象。
当 entry 是个字符串的时候:

module.exports = {
entry: ‘./main.js‘
};

当 entry 是个数组的时候,里面同样包含入口 js 文件,另外一个参数可以是用来配置 webpack 提供的一个静态资源服务器,webpack-dev-server。webpack-dev-server 会监控项目中每一个文件的变化,实时的进行构建,并且自动刷新页面:

module.exports = {
entry: [
‘webpack/hot/only-dev-server‘,
‘./main.js‘
]
};

当 entry 是个对象的时候,我们可以将不同的文件构建成不同的文件,按需使用:

module.exports = {
entry: {
a: ‘./a.js‘,
b: ‘./b.js‘
}
};

output 用于定义构建后的文件的输出,是个对象。其中包含path和filename:

module.exports = {
output: {
path: ‘./build‘,
filename: ‘bundle.js‘
}
};

如果有多个入口文件分开打包,可以通过[name]来命名打包的输出文件。

module.exports = {
entry: {
a: "./a",
b: "./b",
c: ["./c", "./d"]
},
output: {
path: path.join(__dirname, "dist"),
filename: "[name].entry.js"
}
};

具体使用参考官网
entry以及output部分

module
module 主要是用来配置加载器(Loaders),包括loaders、preLoaders、postLoaders、noParse。
webpack 本身只能处理 JavaScript 模块,如果要处理其他类型的文件,就需要使用 loader 进行转换,本文第六章将会介绍一些常用的 Loaders。

loaders、preLoaders、postLoaders的配置选项包括以下几方面:

  • test: 一个匹配loaders所处理的文件的拓展名的正则表达式(必须)
  • loader: loader的名称(必须)
  • include/exclude: 手动添加必须处理的文件/文件夹,或屏蔽不需要处理的文件/文件夹(可选)
  • query: 为loaders提供额外的设置选项(可选)
module.exports = {
module: {
preLoaders: [
{test: /\.js$/, loader: "eslint-loader", exclude: /node_modules/} //打包前使用eslint检测js
],
loaders: [
{test: /\.less$/, loader: ‘style-loader!css-loader!less-loader‘ }, //处理css文件,把less编译成css
{test: /\.(png|jpg)$/, loader: ‘url-loader?limit=8192‘} // 处理图片,大小低于8k的文件编译为base64
]
}
};

noParse是 webpack 的一个很有用的配置项,如果你确定一个模块中没有其它新的依赖就可以配置这项,webpack 将不再扫描这个文件中的依赖。

module: {
noParse: [/moment-with-locales/]
}

具体使用参考官网module部分
官网也收集了常用的 Loaders 列表:list-of-loaders

resolve
resolve 用来配置文件路径的指向。可以定义文件跟模块的默认路径及后缀等,节省 webpack 搜索文件的时间、优化引用模块时的体验。常用的包括alias、extensions、root、modulesDirectories属性:

  • alias:是个对象,把资源路径重定向到另一个路径,比如require(‘React’)默认引用的是 /node_modules/react.js,我们可以定义用react.min.js替代
    //webpack.config.js
    ...
    resolve: {
    alias: {
    ‘someutil‘: path.join(__dirname, ‘./src/util/someutil‘),
    ‘react-dom‘: path.join(nodeModulesPath,‘react-dom/dist/react-dom.min‘)
    }
    }
    ...
    //app.js
    //配置resolve.alias前
    import react-dom form ‘react-dom‘ //此时默认载入‘/node_modules/react-dom/dist/react-dom.js‘
    import someutil form ‘../../src/util/someutil‘ //需要定位该文件相对位置
    //配置resolve.alias后
    import react-dom form ‘react-dom‘ //此时载入压缩后的‘react-dom.min.js‘
    import someutil form ‘someutil‘ //不需要再写相对位置,因为已在resolve.alias中定义
  • extensions:是个数组,定义资源的默认后缀,比如定义后引用a.js、b.json、c.css等资源可以不用写后缀名直接写a、b、c
    //webpack.config.js
    ...
    resolve: {
    extensions: [‘‘, ‘.js‘, ‘.jsx‘, ‘.json‘, ‘.css‘]
    }
    ...
    //app.js
    //配置resolve.extensions前
    import a form ‘a.js‘
    import b form ‘b.json‘
    import c form ‘c.css‘
    //配置resolve.extensions后
    import a form ‘a‘
    import b form ‘b‘
    import c form ‘c‘
  • root:是个数组,通过绝对路径的方式来定义查找模块的文件夹。可以是一个数组,主要是用来增加模块的搜寻位置使用的。root 的值必须是绝对路径,使用path.resolve设置。
    //webpack.config.js
    var path = require(‘path‘);
    resolve: {
    root: [
    path.resolve(‘./app/modules‘),
    path.resolve(‘./vendor/modules‘)
    ]
    }
    //这样设置后,会增加搜索app/modules和vendor/modules下所有node_modules里面的模块。
  • modulesDirectories:是个数组,是用来设置搜索的目录名的,默认值:[“web_modules”, “node_modules”]。如果把值设置成[“mydir”], webpack会查询“./mydir”, “../mydir”, “../../mydir”等。
    //webpack.config.js
    ...
    resolve: {
    modulesDirectories: [‘node_modules‘, ‘./src/component‘]
    }
    ...
    //app.js
    //配置resolve.modulesDirectories前
    import a form ‘../../src/component/a‘
    import b form ‘../../src/component/b‘
    //配置resolve.modulesDirectories后
    import a form ‘a‘
    import b form ‘b‘

具体使用参考官网resolve部分

plugins
插件,比 loader 更强大,能使用更多 webpack 的 api。webpack 本身内置了一些常用的插件,还可以通过 npm 安装第三方插件。本文第七章将会介绍一些常用的插件。

var HtmlWebpackPlugin = require(‘html-webpack-plugin‘);
module.exports = {
plugins: {
new webpack.optimize.OccurenceOrderPlugin(), //为组件分配ID
new webpack.HotModuleReplacementPlugin(), //热加载插件
new webpack.optimize.UglifyJsPlugin(), //压缩混淆js
new webpack.NoErrorsPlugin(),//跳过编译时出错的代码并记录
new ExtractTextPlugin(‘[name]-[hash:5].min.css‘) //将css单独打包并重命名
}
}

具体使用参考官网内置 plugins 列表list-of-plugins部分,这里有所有内置插件的详细使用说明。

externals
当我们想在项目中require一些其他的类库或者API,而又不想让这些类库的源码被构建到运行时文件中。例如 React、jQuery 等文件我们想使用 CDN 的引用,不想把他们打包进输出文件。就可以通过配置 externals 参数来配置:

module.exports = {
externals: {
jQuery: true
}
};

然后在页面里引入< script src="//cdn/jquery.min.js">
这样 jQuery 就不用打包了,直接指向 windows.jQuery 就好
externals部分

其他

除以上 6 个常用配置属性外,webpack 的配置属性还有contextcacheprofile等等,个人觉得并不常用,各位可以前往官网configuration详细查看。

常用 Loaders 介绍

babel-loader
babel-loader 用来编译下一代 JavaScript,比如 ES6、React 等,编译 ES6、React 的话还需要安装 babel-preset-es2015、babel-preset-react。

eslint-loader
配合eslint用来规范纠错 js,你可能同时还会需要babel-eslint、eslint-plugin-react。

style-loader、css-loader、less-loader、sass-loader
处理 css、less、sass 文件

postcss-loader
用 postcss 来处理 CSS,最被常用的是其autoprefixer插件

resolve-url-loader
用来解析 css 里的 url() 声明里的文件的相对路径,使用 css-loader 时一般也必须要同时使用 resolve-url-loader

file-loader
用来处理文件名及路径,比如给文件添加 hash,返回文件相对路径等。

url-loader
与上面的 file-loader 类似,但是当文件小于设定的 limit 时可以处理成 Data Url(base 64)。

raw-loader
把文件内容作为字符串返回。例如var fileContent = require(‘raw!./file.txt’),这里把./file.txt的内容作为字符串返回。

imports-loader
用于向一个模块的作用域内注入变量。
举个栗子,比如我们需要使用bootstrap.js,这个文件虽然依赖jQuery但其内部没有require(‘jquery’),这导致文件内的jQuery对象不可识别,所以模块化调用bootstrap.js时就会报错jQuery is not defined`。使用 imports-loader 的话:

require(‘imports?jQuery=jquery!bootstrap/dist/js/bootstrap‘);

imports-loader 会在 bootstrap 的源码前面,注入如下代码:

/* IMPORTS FROM imports-loader */
var jQuery = require("jquery");

exports-loader
用于向一个模块中提供导出模块功能。功能与imports-loader类似,但他是在文件的最后添加一行。
举个栗子,比如file.js中没有调用export导出模块,或者没有define定义模块,因此无法模块化调用它。可以使用 exports-loader:

require("exports?file,parse=helpers.parse!./file.js");

他会在./file.js文件的最后添加如下代码:

/* EXPORTS FROM exports-loader */
exports["file"] = (file);
exports["parse"] = (helpers.parse);

expose-loader
这个 loader 是将某个对象暴露成一个全局变量。
举个栗子,比如把jQuery对象暴露成全局变量。这样,那些bootstrap.js之类的文件就都能访问这个变量了。

module: {
loaders: [
{ test: require.resolve("jquery"), loader: "expose?$!expose?jQuery" },
]
}

react-hot-loader
React 的网页热加载刷新 loader。同时需要配合使用 webpack-dev-server 。

常用插件介绍

具体的使用方法请在官网list-of-plugins查询,本文只简单介绍几个常用插件。

CommonsChunkPlugin

插件用法比较多,常用的是把一些不经常更改的公共组件合并压缩成一个 common 文件。有些类库如utils, bootstrap之类的可能被多个页面共享,最好是可以合并成一个js,而非每个js单独去引用。这样能够节省一些空间。

似乎只有在多入口文件时才能把公共文件提取出来,但一般模块化都建议单入口文件,所以个人觉得这个插件对我并没有什么卵用,有多入口需求的同学可以使用。

extract-text-webpack-plugin

第三方插件,将 CSS 打包成独立文件,而非内联。

HotModuleReplacementPlugin

代码热替换。

HtmlWebpackPlugin

生成 HTML 文件,配合 ExtractTextPlugin 可以加入打包后的 js 和 css。

NoErrorsPlugin

报错但不退出 webpack 进程。

OccurenceOrderPlugin

通过计算模块出现次数来分配模块。通过这个插件webpack可以分析和优先考虑使用最多的模块,并为它们分配最小的ID。这个经常被使用可以较快地获得模块。这使得模块可以预读,建议这样可以减少总文件大小。

ProvidePlugin

定义一个共用的插件入口。

new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery"
})

这样就可直接在文件中使用$,无需再require(‘jQuery’)。

UglifyJsPlugin

js 代码压缩混淆 。

DedupePlugin

我的编程学习网——分享web前端后端开发技术知识。 垃圾信息处理邮箱 tousu563@163.com 网站地图
icp备案号 闽ICP备2023006418号-8 不良信息举报平台 互联网安全管理备案 Copyright 2023 www.wodecom.cn All Rights Reserved