webpack
是一个当下最流行的前端资源的模块打包器。当 webpack
处理应用程序时,它会递归地构建一个依赖关系图(dependency graph
),其中包含应用程序须要的每一个模块,而后将全部这些模块打包成少许的bundle
- 一般只有一个,由浏览器加载。css
它是高度可配置的,咱们先理解四个核心概念:入口(entry
)、输出(output
)、loader、插件(plugins
)html
webpack 建立应用程序全部依赖的关系图。图的起点被称之为入口起点(entry point
)。入口起点告诉 webpack 从哪里开始,并根据依赖关系图肯定须要打包的内容。能够将应用程序的入口起点认为是根上下文或 APP第一个启动文件。前端
简单规则:每一个 HTML 页面都有一个入口起点。单页应用(SPA):一个入口起点,多页应用(MPA):多个入口起点。node
用法:entry: string | Arrary<string>
webpack
//webpack.config.js module.exports = { entry: './src/index.js' };
entry
属性的单个入口语法,在扩展配置的时候有失灵活性。它是下面的简写:web
//webpack.config.js module.exports = { entry: { main: './src/index.js' } };
向entry
传入一个数组时候,将建立"多个主入口(multi-main entry)"。在你想要多个依赖文件一块儿注入,而且将他们的依赖导向(graph)到一个"chunk"时候,传入数组的方式就颇有用。shell
//webpack.config.js module.exports = { entry: [ './src/index.js', 'babel-polyfill', ] };
用法: entry: {[entryChunkName: string]: string|Array<string>}
npm
//webpack.config.js module.export = { entry: { app: './src/app.js', vendors: './src/vendors.js' } };
对象语法会比较繁琐。然而,这是应用程序中定义入口的最可扩展的方式。json
这个配置告诉咱们 webpack 从 app.js
和 vendors.js
开始建立依赖图。这些依赖图是彼此彻底分离、互相独立的。这种方式比较常见于,只有一个入口起点(不包括 vendor
,vendor
通常都是动态加载的第三方模块。动态加载的模块不是入口起点。)的单页应用程序(single page application)中。不过,为了支持提供更佳 vendor
分离能力的 DllPlugin
。 官方如今不太建议将第三方模块放到entry.vendors
中。api
对象语法,更常见的应该是多入口应用程序-多页应用(MPA)。
//webpack.config.js module.export = { entry: { home: "./home.js", about: "./about.js", contact: "./contact.js" } };
此配置,告诉 webpack,咱们 须要 3 个独立分离的依赖关系图.
在多页应用中,每当页面跳转时,服务器将为你获取一个新的 HTML 文档。页面从新加载新文档,而且资源被从新下载。
根据经验:每一个 HTML 文档只使用一个入口起点。
将全部的资源(assets)归拢在一块儿后,还须要告诉 webpack 在哪里打包应用程序。webpack 的 output
属性描述了如何处理归拢在一块儿的代码(bundled code)。output
选项能够控制webpack如何向硬盘写入编译文件。注意,即便能够存在多个entry
起点,但只指定一个output
配置。
在 webpack 中配置output
属性的最低要求是,将它的值设置为一个对象,包括如下两点:
filename
用于输出文件的文件名。path
的绝对路径。//webpack.config.js module.exports = { entry: './src/index.js', output: { path: './home/proj/public/assets', filename: 'bundle.js' } };
此配置将一个单独的 bundle.js
文件输出到 ./home/proj/public/assets
目录中。
若是配置建立了多个单独的 "chunk"
(例如,使用多个入口起点或使用像 CommonsChunkPlugin
这样的插件),则应该使用占位符来确保每一个文件具备惟一的名称。
{ entry: { app: './src/app.js', search: './src/search.js' }, output: { filename: '[name].js', //使用占位符 path: __dirname + '/dist' } } // 写入到硬盘:./dist/app.js, ./dist/search.js
webpack的目标是,让webpack聚焦于项目中的全部资源(asset), 而浏览器不须要关注考虑这些。 webpack把每一个文件(.css
, .html
, .scss
, .jpg
, etc.
)都做为模块处理。然而webpack自身只理解JavaScript。
webpack loader 在文件被添加到依赖图中时,将文件源代码转换为模块。
loader
可使你在import
或"加载"模块时预处理文件。所以,loader
相似于其余构建工具中“任务(task)”,并提供了处理前端构建步骤的强大方法。
在更高层面,在webpack的配置中loader
有两个目标:
loader
进行转换的那些文件。(test
属性)use
属性)//webpack.config.js const path = require('path'); module.exports = { entry: './path/to/my/entry/file.js', output: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' }, module: { rules: [ { test: /\.txt$/, use: 'raw-loader' } ] } };
以上配置中,对一个单独的 module
对象定义了 rules
属性,里面包含两个必须属性:test
和use
。这至关于告诉 webpack 编译器,当碰到「在 require()/import
语句中被解析为 .txt
的路径」时,在对它打包以前,先使用 raw-loader
转换一下。
在webpack配置中定义
loader
时,要定义在module.rules
中,而不是rules
。若是不这么作,webpack会给出严重警告
例如,你可使用loader
告诉webpack加载css
文件,或者将TypeScript转为JavaScript。为此,首先安装相对应的loader
:
npm install -D css-loader npm install -D ts-loader
而后指示webpack对每一个.css
使用css-loader
, 以及对全部.ts
文件使用ts-loader
:
module.exports = { module: { rules: [ { test: /\.css$/, use: 'css-loader' }, { test: /\.ts$/, use: 'ts-loader' } ] } };
根据配置选项,下面的规范定义了同等的loader
用法:
{test: /\.css$/, use: 'css-loader'} // 等同于 {test: /\.css$/, use: [{ loader: 'css-loader' }]} // 等同于 {test: /\.css$/, loader: 'css-loader'}
module.rules.loader
是 module.rules.use: [ { loader } ]
的简写。
在应用程序中,有三种使用loader的方式:
imort
语句中显示指定loader。shell
命令中指定它们。module.rules
容许你在 webpack 配置中指定多个 loader
。 这是展现loader
的一种简明方式,而且有助于使代码变得简洁。同时让你对各个loader
有个全局概览:
module: { rules: [{ test: /\.css$/, use: [ 'style-loader', { loader: 'scss-loader' }, { loader: 'css-loader', options: { modules: true } } ] }] }
能够在 import
语句或任何等效于 "import" 的方式中指定 loader。使用 !
将资源中的 loader 分开。分开的每一个部分都相对于当前目录解析。
import Styles from 'style-loader!css-loader?modules!./styles.css'
经过前置全部规则及使用!
, 能够对应覆盖到配置中的任意loader
。
选项能够传递查询参数,例如 ?key=value&foo=bar
,或者一个 JSON 对象,例如 ?{"key":"value","foo":"bar"}
。
尽量使用
module.rules
,由于这样能够减小源码中的代码量,而且能够在出错时,更快地调试和定位 loader 中的问题。
你也能够经过CLI
使用loader:
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
这会对 .jade
文件使用 jade-loader
,对 .css
文件使用 style-loader
和 css-loader
。
options
对象进行配置。package.json
常见的 main
属性,还能够将普通的 npm 模块导出为loader,作法是在 package.json
里定义一个 loader
字段。loader 遵循标准的模块解析。多数状况下,loader 将从模块路径(一般将模块路径认为是npm install
, node_modules
)解析。
loader 模块须要导出为一个函数,而且使用 Node.js 兼容的 JavaScript 编写。一般使用 npm 来管理,也能够将自定义 loader 做为应用程序中的文件。按照约定,loader 一般被命名为 xxx-loader(例如 json-loader
)。
插件是 wepback 的支柱功能。webpack 自身也是构建于-你在 webpack 配置中用到的相同的插件系统之上!
插件目的在于解决 loader没法实现的其余事。
因为loader仅在每一个文件的基础上执行转换,而插件(plugins) 经常使用于(但不限于)在打包模块的 “compilation” 和 “chunk” 生命周期执行操做和自定义功能。想要使用一个插件,你只须要 require()
它,而后把它添加到 plugins
数组中。
多数插件能够经过选项(option)自定义。你也能够在一个配置文件中由于不一样目的而屡次使用同一个插件,这时须要经过使用 new 来建立它的一个实例。
webpack 插件是一个具备 apply
属性的 JavaScript 对象。apply
属性会被 webpack compiler 调用,而且 compiler
对象可在整个编译生命周期访问。经过Function.prototype.apply
方法,你能够把任意函数做为插件传递(this
将指向compiler
)。咱们能够在配置中使用这样的方式来内联自定义插件。
//ConsoleLogOnBuildWebpackPlugin.js function ConsoleLogOnBuildWebpackPlugin() { }; ConsoleLogOnBuildWebpackPlugin.prototype.apply = function(compiler) { compiler.plugin('run', function(compiler, callback) { console.log("webpack 构建过程开始!!!"); callback(); }); };
因为插件能够携带参数/选项,你必须在webpack配置中,向plugins
属性中传入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: { path: path.resolve(__dirname, 'dist'), filename: 'my-first-webpack.bundle.js' }, module: { rules: [ { test: /\.txt$/, use: 'raw-loader' } ] }, plugins: [ new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'}) ]0 }; module.exports = config;
即使使用 Node API,用户也应该在配置中传入 plugins 属性。compiler.apply
并非推荐的使用方式。
// some-node-script.js const webpack = require('webpack'); //访问 webpack 运行时(runtime) const configuration = require('./webpack.config.js'); let compiler = webpack(configuration); compiler.apply(new webpack.ProgressPlugin()); compiler.run(function(err, stats) { // ... });
以上就是webpack中比较重要的四个概念,在平时开发过程当中会常常遇到。里面还能够有不少的详细配置,须要咱们在项目开发的过程当中慢慢了解。