浅谈webpack2--学会配置(一)

webpack作为包管理器,已经推出很多年了。在学习webpack之前,其实需要搞明白为什么要使用它,毕竟打包工具也有很多,比如:gulp,grunt,browserify,fis。

为什么使用webpack?

换句话说,webpack的特色是什么,有什么值得我们使用的:

  • 根据文件(模块)之间的依赖关系,拆分成块,并按需进行异步加载。
  • 强大的Loaders功能,将一切资源转化合适的格式,以共环境使用。
  • 将一切资源视为块,进行打包转换,比如:传统的js模块(amd,cmd等),图片,less等。
  • 丰富并具有扩展性的插件功能。

webpack和gulp的优势在哪?gulp主要是对文件的编译,压缩等功能,简化前端开发流程。webpack侧重在梳理模块之间的关系,将文件进行拆分,然后重新组合生成新的单个或多个文件,并利用加载器和插件进行
编译,压缩功能。

webpack之Entry

最简单配置,单入口:
1
2
3
module.exports ={
entry: './src/index.js'
}

上面的等同于:

1
2
3
4
5
module.exports ={
entry: {
main:'./src/index.js'
}
}

这里的index.js文件就是入口文件,导入到名称为main的chunk里面。如果需要将多个依赖导入到一个chunk里面,可以给entry中直接传入数组或者对象的值为数组。

分离公共库

将公共库从应用程序中分离出来。

1
2
3
4
5
6
module.exports ={
entry: {
main:'./src/index.js',
vendors:['react', 'react-dom']
}
}

使用CommonsChunkPlugin插件,将main依赖vendors部分提取到vendors的bundle中,通过__webpack_require__()调用。
提示:对象的key可以为目录形式。

webpack之Output

输出配置:

1
2
3
4
5
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
}

path

文件输出路径,资源存储路径。

publicPath

处理静态资源引用地址,比如:css,html等。

1
background: url(../images/yeoman.png);

输出:

1
background: url(/dist/42092f929161dae9c08a21bfb46ece4d.png);

filename

文件输出名称

1
2
filename: '[name].[hash].js' //或
filename: '[name].[chunkhash].js'

name:chunk的Name。
id:chunk的Id。
hash:compilation生命周期的hash替换。
chunkhash”被chunk的hash替换。

chunkFilename

非入口的chunk文件名称(非entry配置中文件)

sourceMapFilename

sourceMap文件的名称。
参数: [id],[file],[hash]
默认: [file].map

jsonpFunction

异步加载的chunk的JSONP函数。
默认:webpackJsonp

了解更多官网output

webpack之Module

noParse

确认模块中没有其他依赖的情况下,设置noParse,webpack不会解析对应文件生成AST,并不会去寻找文件中的依赖。
缩短了打包时间。
参数:/jquery/[/jquery/]

rules

定义解析规则,按照规则,模块将有各自的创建方式。

事例:

1
2
3
4
5
6
7
8
9
10
rules:[{
test:/\.js$/
use:{
loader:'babel-loader',
options:{
"presets": ['es2015','react']
}
},
exclude:[path.join(APP_PATH, 'lib')],
}]

每个rule分为三部分:条件,结果,嵌套规则。听到这里大脑里晕乎乎的,下面将解释这些内容。

rule条件

当满足所有匹配条件的文件,才会被rule解析。条件的入参有2种类型:

  1. 请求的资源的绝对路径,名称:resource
  2. 发起请求的资源绝对路径 , 名称:issuer

    举个栗子:
      a.js 文件中import “./a.css”。  
      那么,a.js的绝对路径就是issuer;
      a.css的绝对路径就是resource;

    其中,test,include,exclude和resource对resource匹配,属性issuer对issuer匹配。

rule结果

条件满足后,rule结果才会执行。
还是有点晕,对吧。好比,if语句外面的是条件,括号里面的是执行内容,这里的rule结果就像是执行内容。
rule结果也有2种类型:

  1. 加载器loader:将resource类型资源文件进行转换。(使用过webpack的都比较熟悉loader)
  2. 解析器parser:解析器配置选项。(后面会详细解释)

rule嵌套

需要满足条件才能起作用。
通过rule.oneOf和rules配置。

官网代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
test: /.css$/,
oneOf: [
{
resourceQuery: /inline/, // foo.css?inline
use: 'url-loader'
},
{
resourceQuery: /external/, // foo.css?external
use: 'file-loader'
}
]
}
foo.css?inline将被url-loader执行,同理。

rule部分参数

  • test:判断条件,resource类型。
  • exclude:排除resource类型文件目录。
  • include:包含的resource类型文件目录。
  • loader:Rule.use:[{loader}]的简写。如:loader:'style-loader!css-loader',不建议使用。
  • options:Rule.use:[{options}]的简写。如:options:{key:vlaue}
  • use:包含loader属性,可选属性options。loader属性中配置需要使用的加载器,options为加载器参数。例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    { test:/.less$/,
    use:[
    'style-loader',
    [loader:'css-loader',
    option:{
    'importLoaders':1
    }],
    'less-loader'
    ]
    }
  • resourceQuery:资源匹配参数。如:foo.css?inline

  • enforce:用于替代webpack中 preLoaders和postLoaders。设置loader的种类。值为:’pre’或’post’。例子:

    1
    2
    3
    4
    5
    6
    {
    test: /\.(js|jsx)$/,
    loader: 'eslint-loader',
    enforce:pre
    }
    //代替preLoaders

    loader种类分为4种:后置, 行内, 普通, 前置。执行顺序如名称,一目了然。行内是在require或import中使用的loader,例子:

    1
    2
    3
    require("!my-loader!./my-module") 禁止preloaders生效。
    require("!!my-loader!./my-module") 禁止在配置文件中的所有加载器生效。
    require("-!my-loader!./my-module") 禁止loader和preloader,不禁止postloader。
  • parser:解析选项对象。对解析器插件进行设置。大部分设置为布尔类型的值,少部分可以是其他。官网例子:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    parser: {
    amd: false, // 禁用 AMD
    commonjs: false, // 禁用 CommonJS
    system: false, // 禁用 SystemJS
    harmony: false, // 禁用 ES2015 Harmony import/export
    requireInclude: false, // 禁用 require.include
    requireEnsure: false, // 禁用 require.ensure
    requireContext: false, // 禁用 require.context
    browserify: false, // 禁用特殊处理的 browserify bundle
    requireJs: false, // 禁用 requirejs.*
    node: false, // 禁用 __dirname, __filename, module, require.extensions, require.main 等。
    node: {...} // 在模块级别(module level)上重新配置 node 层(layer)
    }

    光是例子,大家似乎还是不太明白。实际操作:入口文件app.js中输入console.log(__dirname),然后执行打包,编译生成文件中生成了一个理解
    执行函数function(module, __dirname),第二个参数为__dirname。当在配置文件中设置parser:{node:false}之后,编译后生成文件
    中,没有这个执行函数。说到这里,大家都懂了吧。

    webpack之Resolve

    设置模块的解析方式。

    属性

  • alias:设置模块别名

    1
    2
    {newName : path/xxx/xxx } //newName是别名 require('newName') eq require('path/fileName')
    {newName$ : path/xxx/xxx } //精准匹配 不能 require('newName/path/file');
  • modules:解析的模块名称,解析根据配置,具有先后顺序。 {modules:[path.join(__dirname,"./src"),'node_modules']}

  • extensions:扩展名称设置,设置后自动解析,无需在添加 {extensions:['.js','.jsx']}
  • enforceExtension:强制禁止或允许省略扩展名,布尔类型
  • descriptionFiles:设置解析时,对应引用模块(import React from ‘react’)的描述文件,模块将根据描述文件导入。默认:descriptionFiles:['package.json']例如:

    1
    2
    3
    4
    入口文件中:import React from 'react'; //文件中只有这行引用,因为修改描述文件将影响所有模块
    配置:`descriptionFiles:['package1.json']`//运行将会报错: Can't resolve 'react' in '/User.....'
    修改 react 模块中的package.json为package1.json ,再次运行,执行成功。
    所以,一般这个属性不会修改。
  • mainFields:设置使用引入模块的package.json文件中哪个属性,来进行导入模块。例如:

    1
    2
    3
    4
    配置:`mainFields:['newmain']` //执行入口文件。报错:Can't resolve 'react' in '/User.....'
    修改react的package.json中新增 newmain:"react.js"
    再次运行,执行成功。
  • mainFiles:解析目录时默认的文件名。默认:mainFiles: ["index"]。例如:
    import 'components/path/' eq import 'components/path/index'
    当设置mainFiles: ["main"]时,import 'components/path/'eqimport 'components/path/main'

    webpack之plugins

    webpack插件为webpack提供了更加强大的功能。插件分为内置和外置两种类型。之后的文章,我将详细讲解,插件使用,原理和自己编写插件。这里就不在描述了。