Webpack之恋(3)—深入核心概念

楔子

4种核心概念解析结尾所述Webpack的entry,output,loaders,plugins有更多的定义与配置,本文就来一探究竟。
webpack

entry(入口)

entry相当于应用程序的main入口,webpack定义entry有两种方式。

简写定义

语法

entry: string|Array<string>

示例

// webpack.config.js

const config = {
entry: './path/to/my/entry/file.js'
};

module.exports = config;

其实这是下面即将要介绍的对象定义的简写法,属性entry相当于

const config = {
entry: {
main: './path/to/my/entry/file.js'
}
};

entry也可以是数组,相当于多个entry入口,如

const config = {
entry: [
'./path/to/my/entry/file.js',
'./path/to/my/entry/app.js'
]
};

每个入口都代表一个独立的逻辑单元。

对象式定义

这种方式是最基本的,语法

entry: {[entryChunkName: string]: string|Array<string>}

示例

const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};

output(产出物)

选项设置影响构建的output,output告诉webpack如何写产出到磁盘。虽然入口可以有多个,但output却只有一个配置属性。

语法

最小需求的webpack配置文件中的output属性至少包括:

  • filename 指定output的文件名,默认是main.js;
  • path 是存放output文件的绝对地址的目录名;
    const config = {
    output: {
    filename: 'bundle.js',
    path: '/home/proj/public/assets'
    }
    };

    module.exports = config;
选项

output还有需要有用的选项,这些选项影响到output的行为。首先根据上文的配置使用webpack构建后的输出

Hash: b122cfb91c817479c4cd
Version: webpack 2.4.1
Time: 371ms
Asset Size Chunks Chunk Names
vendors.js 544 kB 0 [emitted] [big] vendors
app.js 544 kB 1 [emitted] [big] app
[0] ./~/lodash/lodash.js 540 kB {0} {1} [built]
[1] (webpack)/buildin/global.js 509 bytes {0} {1} [built]
[2] (webpack)/buildin/module.js 517 bytes {0} {1} [built]
[3] ./src/app.js 248 bytes {1} [built]
[4] ./src/vendors.js 248 bytes {0} [built]

chunk 你可以理解为入口entry的每个属性就是一个chunk,比如app: ‘./src/app.js’,vendors: ‘./src/vendors.js’都是chunk。由上面的输出也能看到chunk的id、名称以及编译的哈希值.

  • output.chunkFilename
    非入口文件,但又需要产出到output.path目录中,命名的占位符含义
    • [id] chunk的id,这个是随机的;
    • [name] chunk的名字,如果chunk没有名字就以chunk的id代替;
    • [hash] 编译的哈希值;
    • [chunkhash] chunk的哈希值;
  • output.filename
    设置每个产出在磁盘上的文件名,不能设置为绝对路径,因为它与output.path拼接为完整的路径。对于简写式定义的entry

    {
    entry: './src/app.js',
    output: {
    filename: 'bundle.js',
    path: __dirname + '/build'
    }
    }

    生成一个单一的产出文件./build/bundle.js.而对于对象式入口定义

    {
    entry: {
    app: './src/app.js',
    search: './src/search.js'
    },
    output: {
    filename: '[name].js',
    path: __dirname + '/build'
    }
    }

    output同样支持id,name,hash,chunkhash占位符,具体可参考chunkFilename的描述。分别生成./build/app.js./build/search.js文件。

  • output.path 产出物存放的绝对路径的目录。
  • output.crossOriginLoading 跨域调用chunk设置,默认为false禁止跨域;anonymous匿名调用不发送身份信息;use-credentials认证调用;
  • output.devtoolLineToLine 输入与产出的行到行映射模式,官方建议设置为false禁用;
  • output.hotUpdateChunkFilename hotUpdate是指页面在尽量不经过刷新的情况下将页面引用的资源进行替换,一般用于开发阶段。同样可以使用占位符。
  • output.hotUpdateFunction hotUpdate的chunk异步加载的JSONP函数,默认值为”webpackHotUpdate”。
  • output.hotUpdateMainFilename hotUpdate主文件的名称,支持占位符,默认值为”[hash].hot-update.json”。

loaders(装载器)

由于webpack只懂javascript,因此loader的职能定位就是把一切需要的资源转换成webpack懂得的模块,它可以把别的语言如TypeScript转换成JavaScript,甚至把图片、css等都转换成JavaScript。
使用loader之前需要先安装,如

npm install --save-dev css-loader

安装后使用方式有三种:配置、require、CLI。

配置使用

在webpack的配置文件中配置,语法如

module.exports = {
module: {
rules: [
{test: /\.css$/, loader: 'css-loader'}
// 等同于
{test: /\.css$/, use: 'css-loader'}
// 等同于
{test: /\.css$/, use: {
loader: 'css-loader',
options: {}
}
}
// 等同于(多个可以用数组)
{test: /\.css$/, use: [{
loader: 'css-loader',
options: {}
}]
}
]
}
};

require

可以在require、define、require.ensure等语句中指定loader,多个loader以!隔开

require('style-loader!css-loader?modules!./styles.css');

loader的选项可以使用web query的方式如?key=value&foo=bar,也可以使用json对象的方式如?{“key”:”value”,”foo”:”bar”}

CLI

你也可以通过命令行来使用loader

webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'

使用jade-loader处理.jade文件,使用style-loader和css-loader处理.css文件。

loader的特性
  • loader是可以是链式的,使用管道的方式,只需最后的loader输出JavaScript即可。
  • loader可以是同步,也可以是异步。
  • loader接受query参数,用于配置。
  • loader也可以使用options对象来配置。

插件

插件是作为webpack最强有力的扩展,是loader所不能及的。

原理

webpack插件是一个有apply属性的JavaScript对象,apply被webpack的compiler调用,使得该插件能够访问webpack的整个声明周期。插件实现示例

// ConsoleLogOnBuildWebpackPlugin.js

function ConsoleLogOnBuildWebpackPlugin() {

};

ConsoleLogOnBuildWebpackPlugin.prototype.apply = function(compiler) {
compiler.plugin('run', function(compiler, callback) {
console.log("The webpack build process is starting!!!");

callback();
});
};

使用

插件一般会有参数或选项来实现自定义,因此使用之前需要new来实例化。如何使用取决于你如何使用webpack。
配置文件方式使用

// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); //installed via npm
const webpack = require('webpack'); //to access built-in plugins
const path = require('path');

const config = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
loader: 'babel-loader'
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};

module.exports = config;

Node API方式使用

const webpack = require('webpack'); //to access webpack runtime
const configuration = require('./webpack.config.js');

let compiler = webpack(configuration);
compiler.apply(new webpack.ProgressPlugin());

compiler.run(function(err, stats) {
// ...
});

翟前锋 wechat
欢迎订阅我的微信公众号:zhaiqianfeng!