这次我们主要研究的是webpack框架的相关知识,webpack是一个打包构建的前端框架,用于解决前端开发的模块化问题。

应用场景和纵向比较

说到webpack,肯定你还会想到gulp和grunt这些框架,那么webpack是做什么的呢?他和其他的框架有什么区别呢?我们一起来分析一下。
在这一段落中我们主要对webpack和gulp进行纵向的比较分析:
webpack的根本任务是进行打包,把在一个文件中引用的另外一个文件,都打包在一起。
gulp根本任务是实现自动化,其实我们自己可以写一段node脚本实现所有js文件的压缩。gulp就是封装好脚本来帮我们做这些事
还有:
webpack其实也可以实现js文件的压缩,但是这只不过是在完成打包任务的大背景下,所完成的额外任务

那么使用场景呢?我在什么情况下该用webpack,我在什么情况下该用gulp,笔者认为,这就仁者见仁智者见智了,如果说,你就是在开发工程中为了打包,为了模块化,那么你一定要用webpack啊,还有你希望实现解析sass直接放入html中,那么这可以用webpack实现,在打包的过程中就顺手完成了。但是,你初次之外,还想实现,在上线构建的时候,把图片上传cdn并且替换链接,那么你就需要额外引入gulpwebpackgulp都有自己的长处和短处,分析好这两个框架,你就可以在使用过程中如鱼得水。

基本配置项

基本配置项。我们首先说说如何定义基本配置项,第一是我们可以shell的方式,定义配置,都写在命令行上,但是这种方式不好,配置项一多,执行的命令就特别长。因此我们一般采用的都是配置文件的方式。

const path = require('path');module.exports = {// entry 表示 入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。// 类型可以是 string | object | array   entry: './app/entry', // 只有1个入口,入口只有1个文件entry: ['./app/entry1', './app/entry2'], // 只有1个入口,入口有2个文件entry: { // 有2个入口a: './app/entry-a',b: ['./app/entry-b1', './app/entry-b2']},// 如何输出结果:在 Webpack 经过一系列处理后,如何输出最终想要的代码。output: {// 输出文件存放的目录,必须是 string 类型的绝对路径。path: path.resolve(__dirname, 'dist'),// 输出文件的名称filename: 'bundle.js', // 完整的名称filename: '[name].js', // 当配置了多个 entry 时,通过名称模版为不同的 entry 生成不同的文件名称filename: '[chunkhash].js', // 根据文件内容 hash 值生成文件名称,用于浏览器长时间缓存文件// 发布到线上的所有资源的 URL 前缀,string 类型publicPath: '/assets/', // 放到指定目录下publicPath: '', // 放到根目录下publicPath: 'https://cdn.example.com/', // 放到 CDN 上去// 导出库的名称,string 类型// 不填它时,默认输出格式是匿名的立即执行函数library: 'MyLibrary',// 导出库的类型,枚举类型,默认是 var// 可以是 umd | umd2 | commonjs2 | commonjs | amd | this | var | assign | window | global | jsonp ,libraryTarget: 'umd', // 是否包含有用的文件路径信息到生成的代码里去,boolean 类型pathinfo: true, // 附加 Chunk 的文件名称chunkFilename: '[id].js',chunkFilename: '[chunkhash].js',// JSONP 异步加载资源时的回调函数名称,需要和服务端搭配使用jsonpFunction: 'myWebpackJsonp',// 生成的 Source Map 文件名称sourceMapFilename: '[file].map',// 浏览器开发者工具里显示的源码模块名称devtoolModuleFilenameTemplate: 'webpack:///[resource-path]',// 异步加载跨域的资源时使用的方式crossOriginLoading: 'use-credentials',crossOriginLoading: 'anonymous',crossOriginLoading: false,},// 配置模块相关module: {rules: [ // 配置 Loader{  test: /\.jsx?$/, // 正则匹配命中要使用 Loader 的文件include: [ // 只会命中这里面的文件path.resolve(__dirname, 'app')],exclude: [ // 忽略这里面的文件path.resolve(__dirname, 'app/demo-files')],use: [ // 使用那些 Loader,有先后次序,从后往前执行'style-loader', // 直接使用 Loader 的名称{loader: 'css-loader',      options: { // 给 html-loader 传一些参数}}]},],noParse: [ // 不用解析和处理的模块/special-library\.js$/  // 用正则匹配],},// 配置插件plugins: [],// 配置寻找模块的规则resolve: { modules: [ // 寻找模块的根目录,array 类型,默认以 node_modules 为根目录'node_modules',path.resolve(__dirname, 'app')],extensions: ['.js', '.json', '.jsx', '.css'], // 模块的后缀名alias: { // 模块别名配置,用于映射模块// 把 'module' 映射 'new-module',同样的 'module/path/file' 也会被映射成 'new-module/path/file''module': 'new-module',// 使用结尾符号 $ 后,把 'only-module' 映射成 'new-module',// 但是不像上面的,'module/path/file' 不会被映射成 'new-module/path/file''only-module$': 'new-module', },alias: [ // alias 还支持使用数组来更详细的配置{name: 'module', // 老的模块alias: 'new-module', // 新的模块// 是否是只映射模块,如果是 true 只有 'module' 会被映射,如果是 false 'module/inner/path' 也会被映射onlyModule: true, }],symlinks: true, // 是否跟随文件软链接去搜寻模块的路径descriptionFiles: ['package.json'], // 模块的描述文件mainFields: ['main'], // 模块的描述文件里的描述入口的文件的字段名称enforceExtension: false, // 是否强制导入语句必须要写明文件后缀},// 输出文件性能检查配置performance: { hints: 'warning', // 有性能问题时输出警告hints: 'error', // 有性能问题时输出错误hints: false, // 关闭性能检查maxAssetSize: 200000, // 最大文件大小 (单位 bytes)maxEntrypointSize: 400000, // 最大入口文件大小 (单位 bytes)assetFilter: function(assetFilename) { // 过滤要检查的文件return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');}},devtool: 'source-map', // 配置 source-map 类型context: __dirname, // Webpack 使用的根目录,string 类型必须是绝对路径// 配置输出代码的运行环境target: 'web', // 浏览器,默认target: 'webworker', // WebWorkertarget: 'node', // Node.js,使用 `require` 语句加载 Chunk 代码target: 'async-node', // Node.js,异步加载 Chunk 代码target: 'node-webkit', // nw.jstarget: 'electron-main', // electron, 主线程target: 'electron-renderer', // electron, 渲染线程externals: { // 使用来自 JavaScript 运行环境提供的全局变量jquery: 'jQuery'},stats: { // 控制台输出日志控制assets: true,colors: true,errors: true,errorDetails: true,hash: true,},devServer: { // DevServer 相关的配置proxy: { // 代理到后端服务接口'/api': 'http://localhost:3000'},contentBase: path.join(__dirname, 'public'), // 配置 DevServer HTTP 服务器的文件根目录compress: true, // 是否开启 gzip 压缩historyApiFallback: true, // 是否开发 HTML5 History API 网页hot: true, // 是否开启模块热替换功能https: false, // 是否开启 HTTPS 模式},profile: true, // 是否捕捉 Webpack 构建的性能信息,用于分析什么原因导致构建性能不佳cache: false, // 是否启用缓存提升构建速度watch: true, // 是否开始watchOptions: { // 监听模式选项// 不监听的文件或文件夹,支持正则匹配。默认为空ignored: /node_modules/,// 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高// 默认为300ms aggregateTimeout: 300,// 判断文件是否发生变化是不停的去询问系统指定文件有没有变化,默认每秒问 1000 次poll: 1000},
}

以上我们就是webpack中大部分的配置项,其实我们可以发现,最重要四个是entryoutputloaderplugin分别代表入口,出口,加载器和插件。具体的配置信息和其他的配置项就不一一介绍了。
建议大家看一下webpack的官方文档,具体了解一下每一个配置项的含义,就算都记不下来,也最好有点印象。

原理初探

首先我们看一下webpack的整体原理:
初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
确定入口:根据配置中的 entry 找出所有的入口文件;
编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统。

然后我们再看一下webpack中plugin的原理
在使用htmlWebpackPluin的过程中,发现打包出的index.html文件,js引用了两次,由于自己了解plugin的原理,于是动手写了一个。
webpack 的插件架构主要基于Tapable实现的,这个Tapable就是专注于事件的广播和操作。在webpack的编译过程中会广播很多事件,插件可以自己去监听这些事件,在webpack执行到相应的时机做某些操作,然后插件也可以广播事件。
下面就是具体api的实现了,webpack中有complier对象,代表webpack实例。有编译的具体参数。还有一个complation代表本次编译,有打包的文件等信息。
在complier上面绑定plugin和apply。在回调函数中传入complation对象。

plugins: [function () {this.plugin('done', (stats) => {stats.toJson(true).chunks.filter(c => c.entry).forEach(c => {let fileContent = fs.readFileSync((path.join(BUILD_PATH, 'views/main.pug'))).toString('utf-8')fs.writeFileSync(path.join(BUILD_PATH, 'views/main.pug'), fileContent.replace(/webpack\-bundle.*src="(.*)"/g, (match, p1) => {return match.replace(p1, PUBLIC_PATH + c.files[0])}))})})}
]

常见问题分析

webpack配置中遇到的问题

css-loader中importLoaders=1参数的问题
问题是加载的css文件中import了一个css文件,虽然可以被引入最后的html中,但是引入的css未经过postcss的处理,因此加上了这个,就ok了

Mac平台和Windows平台的差异导致的问题

// 配置entry选项时:
entry: {main: __dirname + '/src/index.js'
}
// /和\的问题
const path = require('path');
const entryPath = path.resolve(__dirname, '/src/index.js');
entry: {main: entryPath
}

不能满足业务需求,自定义plugin的经过
如上

提高webpack构建速度的问题

缩小查找文件的范围
利用loader中的excludeinclude
利用reslove中的moudules,这个可以在require时指明存放第三方模块的路径。

利用动态链接库
利用插件DllPlugin,可以打包出一个个单独的动态链接库文件。原因在于包含大量复用模块的动态链接库只需要编译一次,在之后的构建过程中被动态链接库包含的模块将不会在重新编译,而是直接使用动态链接库中的代码。

开启打包编译多进程
运行在Node.js之上的webpack是单线程模型的,也就是说webpack需要处理的任务需要一件件挨着做,不能多个事情一起做。利用插件HappyPack,webpack中最耗时的就是loader这一步,HappyPack它把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。

提取公共代码
利用CommonsChunkPlugin插件提取公共代码。

用过什么plugin

htmlWebpackPlugin用来自动向html文件中加入js和css的文件引入。
CommonsChunkPlugin可以打包公共部分代码(听说4.0已经不用了)。
HappyPack开启多进程,加快打包速度。

【提高系列】webpack相关知识相关推荐

  1. Next.js踩坑入门系列(七) —— 其他相关知识

    Next.js踩坑入门系列 (一) Hello Next.js (二) 添加Antd && CSS (三) 目录重构&&再谈路由 (四) Next.js中期填坑 (五) ...

  2. 单片机小白学步系列(十) 单片机程序下载相关知识

    注:本篇在写<单片机入门指南系列>之前就已经写过,现在发现这篇比较合理的位置,应该是放在<单片机入门指南系列(六) 单片机最小系统--麻雀虽小,五脏俱全>之后的,但是由于之前考 ...

  3. 单片机小白学步系列(五) 集成电路、封装相关知识

    在前文大家都有见到集成电路的图片,其外形有很多种.在这些芯片中真正起作用的部分是集成在硅片上的晶体管.而我们看到的样子,则是在其外部用外壳进行封装.把硅片上的电路管脚,用导线接引到外部接头处,以便于其 ...

  4. 网络带宽相关知识和计算

    一.带宽 带宽应用的领域非常多,可以用来标识信号传输的数据传输能力.标识单位时间内通过链路的数据量.标识显示器的显示能力. 1. 在模拟信号系统又叫频宽,是指在固定的时间可传输的资料数量,亦即在传输管 ...

  5. 狂补呼叫中心相关知识,将收集的资料贴于此

    狂补呼叫中心相关知识,将收集的资料贴于此: H.323的协议体系 根据1998年H.323第二版,H.323制定了无QoS(服务质量)保证的分组网络 PBN(packet Based Networks ...

  6. 网络打印两个基本端口(LPD和9100)的相关知识

    打印设备和主机的连接方式(printer interface)形态多样,从历史悠久的串口并口到现在流行的网络打印和USB连接,另类的红外连接和蓝牙技术,还有超炫的火线连接(IEEE 1394). 我这 ...

  7. (转载)技术族谱:软件开发相关知识体系的整理心得(图)

    每隔一段时间,就会收到些类似的消息: 怎么学好软件开发? 我已经学完了A,我接下来该学B还是C? 其实这样的问题,真的是一言难复.如何学习,是一个很复杂的话题,尤其是眼下业内的技术名词日新月异,乱花迷 ...

  8. alin的学习之路:加密相关知识(加密和解密,常见加密算法,消息验证码HMAC,数字签名)

    alin的学习之路:加密相关知识(加密和解密,常见加密算法,消息验证码HMAC,数字签名) 1. 加密和解密 1.1 加密的三要素 原始数据 加密操作: 明文 -> 密文 解密操作: 密文 -& ...

  9. 网络协议与网络传输相关知识

    网络协议 1.HTTP/2.0相比较于HTTP/1.1,有哪几项主要改进(请写出至少三种)? HTTP 2.0 的出现,相比于 HTTP 1.x ,大幅度的提升了 web 性能.在与 HTTP/1.1 ...

最新文章

  1. 深度解析VC中的消息(上)
  2. 解决Please ensure that adb is correctly located at 'D:\java\sdk\platform-tools\adb.exe' and can be exe
  3. Reflection.Emit的使用场景、工具包及示例总结
  4. python gui界面 tcp_通过python实现TCP编程
  5. .netcore 分布式事务CAP2.6 快速入门
  6. 【开源项目】C++BASE64图像编解码算法
  7. linux怎么删除exe文件夹,ubuntu linux 批量删除文件
  8. android 保活方案_Android 后台保活手段总结 (上篇)
  9. android中断言_我可以使用断言在Android设备上?
  10. 微软提供Windows USB/DVD Download Tool:刻录WINDOWS安装系统到U盘
  11. 联想式查单词-YourDict
  12. 如何批量将 Word 文档转为 Svg 格式
  13. 如何实现基于 RADIUS 协议的双因子认证 MFA?
  14. Android开发中的Java包的定义
  15. android锁屏壁纸设置,安卓锁屏壁纸怎么换 安卓锁屏壁纸设置教程
  16. mysql 无法创建sock,mysql.sock无法打开的问题
  17. 如何在safri查看网页源代码
  18. 庆科EMW3080 mxos开发环境搭建helloworld编译
  19. 携程商旅酒店直连平台的实践(一)
  20. docker版mongodb数据同步到elasticsearch

热门文章

  1. 自动生成Insert数据的SQL脚本
  2. RosBE生成ReactOS的VS2015工程失败2
  3. Eclipse开发Spring MVC入门示例
  4. 影响软件测试未来的5件事 (译)
  5. 7、Node.js EventEmitter
  6. HDU 1166 敌兵布阵
  7. CF385C Bear and Prime Numbers
  8. GCD学习之dispatch_barrier_async
  9. 【HeadFirst设计模式】8.模板方法模式
  10. 接口、抽象类、方法复写、类Equals方法重写