现代前端开发中,由于要不断的站在巨人的肩膀上前行,导致脚下巨人越来越多。项目结构越来越复杂,用到的技术越来越牛X,html+css+js各自在自己的发展路上一骑绝尘,甩的后方的前端开发者已经看不到前方。
Webpack的出现,将前端不断出现的新模块、新资源、新需求,进行自动化整合、梳理、输出,使得前端开发者更加专注业务需求。
核心和概念
本质上,webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。
什么鬼东西,webpack就是把你写好的只有你自己认识的程序,整理翻译打包成漂亮的,大家都能看的程序。
webpack中有四个核心的概念。 entry、output、loader、plugins。 按照流程这四个概念应该是
- 入口entry(你要从哪里收拾)
- 加载loader(开始收拾)
- 插件plugins(收拾完还觉的不满意就再加点功能)
- 出口output(收拾整理完之后放哪里)
当然这是个基本理解。实际配置文件格式直接去官网上扒个模版就好,这里是个样子。
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' } ] }, plugins: [ new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'}) ] };
不过对于我们这种英文不好的小伙伴,明明是loader,配置里面用的却是module里面的rules,我只想说:神经病啊!
到webpack4.0之后,不用自己添加配置文件也可以直接运行了,这个点赞。
入口(entry)
webpack中提供了多种定义入口属性的方式。提供单个入口语法和对象语法。不过呢,常用的配置方法是对象方法,用来包含你引入的第三方库。比如我常用的vue开发框架,带入到webpack配置文件里面就需要如下配置。
const config = { entry: { app: './src/main.js', vendors: ["vue", "vue-router"] } };
当然,多页面应用程序的也是可以的,直接配置里面配多个入口就行了。
const config = { entry: { pageOne: './src/pageOne/index.js', pageTwo: './src/pageTwo/index.js', pageThree: './src/pageThree/index.js' } };
出口(output)
用来配置打包整理完的文件放哪里,但是有规定,不管单入口还是多入口,都只能放在一个地方。
所以配置信息需要配置输出的文件名filename和输出目录的绝对地址path。输出也分为单入口和多入口配置,但是呢多入口也兼容单入口,所以直接用一个配置就行了。
{ output: { filename: '[name].js', path: __dirname + '/dist' } }
加载器(loader)
laoder一定程度上其实是个翻译器,可以对代码在加载的时候就进行预处理,并且可以将不同的语言文件都转换成可理解的对象,Typescript转化成JavaScript,图片转化成data url,等等。
要想使用loader,就要先安装对应的loader包文件。对css有 css-loader,ts文件有 ts-loader, vue文件有 vue-loader,各种文件、图片、视频使用 url-loader,js转化使用 babel-loader,其他还有 style-loader、file-loader、csv-loader、xml-loader等等。
module.exports = { module: { rules: [ { test: /\.css$/, use: 'css-loader' }, { test: /\.ts$/, use: 'ts-loader' }, { test: /\.vue$/, use: 'vue-loader' }, { test: /\.js$/, use: 'babel-loader' }, { test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, use: 'url-loader' }, { test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, use: 'file-loader' }, ] } };
loader特性
- loader支持链式操作。一个传一个
- loader可同步可异步。
- loader执行再node中,可以执行任何可能的操作
- loader接受查询参数
- laoder能有使用options进行配置
- 除了使用 package.json 常见的 main 属性,还可以将普通的 npm 模块导出为 loader,做法是在 package.json 里定义一个 loader 字段。
- 插件(plugin)可以为 loader 带来更多特性。
- loader 能够产生额外的任意文件。
插件(plugins)
插件属于对loader的补充,loader不能实现的功能都可以在插件中进行。
const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装 const webpack = require('webpack'); //访问内置的插件 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)$/, use: 'babel-loader' } ] }, plugins: [ new webpack.optimize.UglifyJsPlugin(), new HtmlWebpackPlugin({template: './src/index.html'}) ] }; module.exports = config;
webpack官方插件
webpack 有着丰富的插件接口(rich plugin interface)。webpack 自身的多数功能都使用这个插件接口。这个插件接口使 webpack 变得极其灵活。
- AggressiveSplittingPlugin将原来的 chunk 分成更小的 chunk
- BabelMinifyWebpackPlugin使用 babel-minify进行压缩
- BannerPlugin在每个生成的 chunk 顶部添加 banner
- CommonsChunkPlugin提取 chunks 之间共享的通用模块
- CompressionWebpackPlugin预先准备的资源压缩版本,使用 Content-Encoding 提供访问服务
- ContextReplacementPlugin重写 require 表达式的推断上下文
- CopyWebpackPlugin将单个文件或整个目录复制到构建目录
- DefinePlugin允许在编译时(compile time)配置的全局常量
- DllPlugin为了极大减少构建时间,进行分离打包
- EnvironmentPluginDefinePlugin 中 process.env 键的简写方式。
- ExtractTextWebpackPlugin从 bundle 中提取文本(CSS)到单独的文件
- HotModuleReplacementPlugin启用模块热替换(Enable Hot Module Replacement - HMR)
- HtmlWebpackPlugin简单创建 HTML 文件,用于服务器访问
- I18nWebpackPlugin为 bundle 增加国际化支持
- IgnorePlugin从 bundle 中排除某些模块
- LimitChunkCountPlugin设置 chunk 的最小/最大限制,以微调和控制
- chunkLoaderOptionsPlugin用于从 webpack 1 迁移到 webpack 2
- MinChunkSizePlugin确保 chunk 大小超过指定限制
- NoEmitOnErrorsPlugin在输出阶段时,遇到编译错误跳过
- NormalModuleReplacementPlugin替换与正则表达式匹配的资源
- NpmInstallWebpackPlugin在开发时自动安装缺少的依赖
- ProvidePlugin不必通过 import/require 使用模块
- SourceMapDevToolPlugin对 source map 进行更细粒度的控制
- EvalSourceMapDevToolPlugin对 eval source map 进行更细粒度的控制
- UglifyjsWebpackPlugin可以控制项目中 UglifyJS 的版本
- ZopfliWebpackPlugin通过 node-zopfli 将资源预先压缩的版本
文末
当然,本文只是对webpack的最最基本的介绍文档。真正webpack里面可配置的东西太多了,更加输入了解可以直接去通读webpack的官方指南和api文档。