手摸手入门前端--01.webpack4

1.webpack基本概念

  1. 0配置 webpack4如今是支持0配置的
  2. 基本概念 entry output loader plugins mode
  3. file module chunks compiler complilation tapable事件流

2.从0开始配置

  1. 初始化项目 npm init git init
  2. 新增 .gitignore文件 src目录(index.js) webpack.config.js
  3. 安装webpack npm install -D webpack webpack-cli(不推荐全局安装)
  4. 在package.json文件中新增script的build指令(指定mode) 或者使用npx命令
  5. 在webpack.config.js中简单配置entry output(path必须是绝对路径)
  6. 执行npm run build获得打包以后的js文件

3.简单分析下build生成的js文件

  1. 基本架构是一个函数的调用(function(modules) {}) ({key-value})
  2. function内部实现一个__webpack_require__方法(缓存优化)
  3. 函数return webpack_require(入口文件)
  4. 参数是一个对象(webpack3是一个数组),是一个key-value键值对的形式
  5. key是文件的路径"./src/index.js"(项目的根目录的路径)value是函数体

4.基本概念的一些介绍

  1. entry入口 支持多种写法 字符串 数组 对象(多入口)
  2. output出口 path属性必须是绝对路径 filename (emit)
  3. loader webpack自身只支持js文件的处理 其余的模块(css)须要使用loader来作转换
    • loader的多种写法
    • loader暴露的就是一个函数 接收一个source参数
    • 注意loader的执行顺序[style-loader,css-loader]
    • resolveLoader用来配置查找loader的目录(默认是找node_modules的)
  4. plugins 是webpack的一等公民(函数是js的一等公民)
    • plugin比loader执行范围更广的任务
    • tapable的事件流
    • 须要实现一个apply (compiler)方法 参数是compiler
    • compiler对象是webpack中一个很是核心的对象
  5. webpack内部是存在一个时间流tapable的.从entry配置的module开始解析entry依赖的全部module,每找到一个module就根据配置的loader去找对应的转换规则,递归执行,而后将生成的chunk转换为文件输出,在整个过程当中 webpack会在恰当的时机执行plugin中订阅的事件

5.webpack的基本过程介绍

  1. 初始化参数 从配置文件和shell语句读取与合并参数 获得最终的参数
  2. 开始编译 使用上一步获得的参数 初始化compiler对象,加载配置的插件(forEach遍历),执行对象的run方法开始编译
  3. 编译模板 从入口文件出发 根据不一样模块使用对应的loader,找出模块依赖的模块递归执行
  4. 完成模板的编译 获得每一个模块编译的模块和模块之间的依赖关系
  5. 输出资源 根据入口和模块的依赖关系 组装成一个个包含多个模块的chunk 再将每一个chunk转换成一个单独的文件加入到输出列表
  6. 输出完成 肯定好输出内容根据配置的output把文件内容写于到文件系统
  7. webpack会在特定的时间点广播特定的事件 插件再监听到对应的事件就会执行对应的逻辑
  8. plugins的顺序是不关心的(事件的订阅是不分前后的)

6.开始配置webpack.config.js文件

没有上代码是由于我比较蠢 通常都是copy别人的配置 作一些修改(允悲)css

  1. 样式文件的处理
    • css-loder 对样式文件一个路径的处理
    • style-loader 生成style标签
    • less less-loader对less文件的处理
    • node-sass(npm常常按照失败) sass-loder
    • autoprefixer postcss-loader 自动添加浏览器前缀 配置.postcssrc.js文件
    • vue-cli2中使用了utils根据不一样的后缀加载不一样的loader
    • OptimizeCSSPlugin插件 提取css样式文件
    • ExtractTextPlugin替换为MiniCssExtractPlugin插件
  2. 图片 字体图标的处理
    • url-loader 对file-loader的一层封装(能够处理二进制)
  3. 打包出来的只有js文件 要手动的写一个html文件引入 怎么解决
    • 使用html-webpack-plugin插件
    • 能够new多个
  4. 每次都须要build对调试很不友好
    • npm install -D webpack-dev-server 从在本地起一个服务
    • 配置devServer proxy一般会用来解决跨域的问题
  5. 在打包以前想删除以前的dist目录
    • 输出filename定义了hash会根据内容的变化生成不少的文件
    • clean-webpack-plugin插件
    • hash、chunkhash、contenthash的区别?
  6. 拷贝static目录中的资源
    • 使用copy-webpack-plugin插件
  7. 代码规范
    • eslint的检查 配置.eslintrc.js和.eslintignore
    • eslint eslint-loader eslint-plugin-standard eslint-friendly-formatter等
    • 使用husky配置pre-commit在代码git commit以前作检验
  8. js文件的处理
    • 主要就是使用babel来作转换
    • @babel/core babel-loader @babel/preset-env
    • 配置babel.config.js文件 配置presets预设 和plugins 插件
  9. vue项目的配置
    • vue-loader vue-template-compiler vue-style-loader eslint-plugin-vue babel-plugin-transform-vue-jsx vue vuex vue-router axios
    • 须要显示的new VueLoaderPlugin()
    • babel的一些配置 eslint规则的修改
  10. react项目的配置
    • @babel/preset-react @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-syntax-dynamic-import等

7.常见的一些优化

  1. 减小文件的搜索访问 resolve alias exclude mainFields
  2. module.noParse不须要递归解析此模块(ele的UI框架)
  3. dll动态连接库(代码块)将基础模块打包出来到单独的动态连接库中在须要导入的时候直接到链接库中webpack.dll.config.js
  4. 多线程 happypack webpack-parallel-uglify-plugin(js多线程压缩)
  5. cdn 静态资源放在cdn服务器上(注意pubilcPath的配置)
  6. 提取公共代码,代码分离
    • 入口的起点分离 entry分割
    • 懒加载 import在webpack就是个自然的分割器 使用jsonp形式加载的
    • 基础类库 长期缓存
    • 页面之间的公用代码
    • 配置optimization:中的splitChunks(分割代码)
  7. tree shaking剔除无用的死代码做用域等

8.其余一些配置

  1. 懒加载 import npm install @babel/plugin-syntax-dynamic-import
  2. resolve的配置 extensions扩展 alias别名配置
  3. devtool source-map文件 源码映射 定位错误
  4. devServer 这个配置很重要 代理属性 hot https等
  5. 区分不一样环境的配置 cross-env 定义环境变量 webpack-merge作配置的合并

9.vue-cli2升级webpack的过程

  1. 安装最新的webpack webpck-cli webpack-dev-server
  2. 更新一些loader plugin eslint babel的升级使用自动升级工具
  3. webpack相关的 npm install --save-dev webpack@latest webpack-cli webpack-dev-server@latest webpack-dev-middleware@latest webpack-bundle-analyzer@latest webpack-merge@latest
  4. 一些loader的升级npm install --save-dev extract-text-webpack-plugin@latest html-webpack-plugin@latest inject-loader@latest friendly-errors-webpack-plugin@latest copy-webpack-plugin@latest optimize-css-assets-webpack-plugin@latest css-loader@latest file-loader@latest url-loader@latest less-loader@latest postcss-loader@latest
  5. eslint的升级npm install --save-dev eslint@latest eslint-config-standard@latest eslint-friendly-formatter@latest eslint-loader@latest eslint-plugin-import@latest eslint-plugin-node@latest eslint-plugin-promise@latest eslint-plugin-standard@latest eslint-plugin-vue@latest
  6. vue相关的升级npm install --save-dev vue-template-compiler@latest vue-loader@latest vue-style-loader@latest
  7. babel的升级npx babel-upgrade --write --install
  8. mode: 'development'的修改
  9. 删除一些内置的插件 例如webpack.NamedModulesPlugin webpack.NoEmitOnErrorsPlugin
  10. 引入const { VueLoaderPlugin } = require('vue-loader')
  11. 使用mini-css-extract-plugin 替代extract-text-webpack-plugin
  12. 代码分割 将new webpack.optimize改成 optimization: {splitChunks: {}}来配置

10.babel相关

  1. astexplorer.net/ 获取代码对应的ast结构
  2. @babel/core babel核心库 用来实现核心的编译
  3. @babel/types实现类型的判断 生成ast零部件
  4. 使用js parser esprima (webpack使用的是acorn)
  5. 解析生成ast语法树 遍历优化 在生成code 不少都是这样的一个过程 vue的dom diff

11.自定义loader

  1. loader就是暴露出一个function出去 source做为参数
  2. 最后的loader最先调用 传入原始的资源
  3. 异步 async 缓存等
  4. 实现一个less-loader
// css-loader
let less = require('less')
module.exports = function (source) {
  // 将less变成css
  less.render(source, (err, result) => {
   // 将结果给下一个style-loader处理
    this.callback(err, result.css)
  })
}

// style-loader
const path = require('path')
module.exports = function (source) {
  // 建立一个style标签 插入到页面中
  let script = (`
      let style = document.createElement('style')
      style.innerHTML = ${JSON.stringify(source)}
      document.head.appendChild(style)
    `
  )
  return script
}
复制代码

12.自定义plugin

  1. 插件是webpack的一等公民(明确监听的事件 触发的钩子函数)
  2. 两个核心概念 compiler和compilation
  3. compiler对象表明了完整的webpack环境配置 这个对象在启动webpack被一次创建 配置好可操做的设置 在webpack应用一个插件事 接收一个compiler对象的引用 能够用来访问webpack的主环境
  4. compilation对象表明了一次资源版本构建 运行webpack中间件时 每当检测到一个文件的变化 就会建立一个compilation 生成一组新的编译资源 compilation对象提供了不少关键时机的回调 供插件自定义处理使用
  5. 插件须要实现一个apply方法 执行一个hooks(之前使用的时plugins注册)
// 一个没用的插件
class CompilationsPlugin {
  constructor (options) {
    this.options = options
  }
  // 这个apply方法名是固定的
  apply (compiler) {
   // compiler.plugin('compilation', function (compilation) 被废弃的写法
    compiler.hooks.compilation.tap('CompilationsPlugin', (compilation) => {
      // 不一样的hooks类型 async promise类型等
      compilation.hooks.optimize.tap('optimize', () => {
        console.log('资源正在被优化')
      })
    })
  }
}
module.exports = CompilationsPlugin
复制代码
  1. 常见的钩子 不一样的阶段
  2. 初始化阶段
    • 从配置文件和shell语句读取和配置参数获得最终的参数
    • 初始化compiler 全局只有一个compiler 该实例包含了完整的webpack配置 来负责文件监听和启动配置
    • 加载插件 依次调用插件的apply方法 让插件监听事件节点
    • 给插件传入compiler实例的引用 方便调用webpack提供的api
    • entry-option 读取配置的entry实例化对应的entryplugin为递归解析作准备
    • after-plugin 调用完全部内置和配置插件的apply方法
    • after-resolvers 根据配置初始化resolver 负责在文件系统中寻找指定路径的文件
  3. 编译阶段
    • run 启动一次新的编译
    • watch-run 监听模式的编译
    • compile 告诉插件一次新的编译要启动
    • compilation 每次检测到文件变化 一个新的compilation被建立
    • make 从entry开始读取文件 根据不一样文件使用对应的loader作编译 递归
    • after-compiler 一次compilation执行完成
    • 在compilation还有不少消失件 build-module normal-module-loader program seal
  4. 输出阶段
    • should-emit 须要输出的文件准备好
    • emit 肯定要输出的文件
    • after-emit 文件输出完成
    • failed 在编译和输出遇到异常就会退出 直接到failed 能够获取到具体的出错缘由

13.实现一个简单的webpack(mypack)

  1. github.com/Lliuxs/my-w…

14.webpack源码分析

小弟最近准备学习某课网上的webpacck4的教程 分享出来你们一块儿学习
连接:pan.baidu.com/s/1ATq2VIT0…
提取码:rqc2html

相关文章
相关标签/搜索