手摸手入门webpack4
栏目: JavaScript · 发布时间: 5年前
内容简介:没有上代码是因为我比较蠢 一般都是copy别人的配置 做一些修改(允悲)
- 0配置 webpack4现在是支持0配置的
- 基本概念 entry output loader plugins mode
- file module chunks compiler complilation tapable事件流
2.从0开始配置
- 初始化项目 npm init git init
- 新增 .gitignore文件 src目录(index.js) webpack.config.js
- 安装webpack npm install -D webpack webpack-cli(不推荐全局安装)
- 在package.json文件中新增script的build指令(指定mode) 或者使用npx命令
- 在webpack.config.js中简单配置entry output(path必须是绝对路径)
- 执行npm run build得到打包之后的js文件
3.简单分析下build生成的js文件
- 基本架构是一个函数的调用(function(modules) {}) ({key-value})
- function内部实现一个__webpack_require__方法(缓存优化)
- 函数return webpack_require (入口文件)
- 参数是一个对象(webpack3是一个数组),是一个key-value键值对的形式
- key是文件的路径"./src/index.js"(项目的根目录的路径)value是函数体
4.基本概念的一些介绍
- entry入口 支持多种写法 字符串 数组 对象(多入口)
- output出口 path属性必须是绝对路径 filename (emit)
-
loader webpack自身只支持js文件的处理 其他的模块(css)需要使用loader来做转换
- loader的多种写法
- loader暴露的就是一个函数 接收一个source参数
- 注意loader的执行顺序[style-loader,css-loader]
- resolveLoader用来配置查找loader的目录(默认是找node_modules的)
-
plugins 是webpack的一等公民(函数是js的一等公民)
- plugin比loader执行范围更广的任务
- tapable的事件流
- 需要实现一个apply (compiler)方法 参数是compiler
- compiler对象是webpack中一个非常核心的对象
- webpack内部是存在一个时间流tapable的.从entry配置的module开始解析entry依赖的所有module,每找到一个module就根据配置的loader去找对应的转换规则,递归执行,然后将生成的chunk转换为文件输出,在整个过程中 webpack会在恰当的时机执行plugin中订阅的事件
5.webpack的基本过程介绍
- 初始化参数 从配置文件和 shell 语句读取与合并参数 得到最终的参数
- 开始编译 使用上一步得到的参数 初始化compiler对象,加载配置的插件(forEach遍历),执行对象的run方法开始编译
- 编译模板 从入口文件出发 根据不同模块使用对应的loader,找出模块依赖的模块递归执行
- 完成模板的编译 得到每个模块编译的模块和模块之间的依赖关系
- 输出资源 根据入口和模块的依赖关系 组装成一个个包含多个模块的chunk 再将每个chunk转换成一个单独的文件加入到输出列表
- 输出完成 确定好输出内容根据配置的output把文件内容写于到文件系统
- webpack会在特定的时间点广播特定的事件 插件再监听到对应的事件就会执行对应的逻辑
- plugins的顺序是不关心的(事件的订阅是不分先后的)
6.开始配置webpack.config.js文件
没有上代码是因为我比较蠢 一般都是copy别人的配置 做一些修改(允悲)
-
样式文件的处理
- 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插件
-
图片 字体图标的处理
- url-loader 对file-loader的一层封装(可以处理二进制)
-
打包出来的只有js文件 要手动的写一个html文件引入 怎么解决
- 使用html-webpack-plugin插件
- 可以new多个
-
每次都需要build对调试很不友好
- npm install -D webpack-dev-server 从在本地起一个服务
- 配置devServer proxy通常会用来解决跨域的问题
-
在打包之前想删除之前的dist目录
- 输出filename定义了hash会根据内容的变化生成很多的文件
- clean-webpack-plugin插件
- hash、chunkhash、contenthash的区别?
-
拷贝static目录中的资源
- 使用copy-webpack-plugin插件
-
代码规范
- eslint的检查 配置.eslintrc.js和.eslintignore
- eslint eslint-loader eslint-plugin-standard eslint-friendly-formatter等
- 使用husky配置pre-commit在代码git commit之前做检验
-
js文件的处理
- 主要就是使用babel来做转换
- @babel/core babel-loader @babel/preset-env
- 配置babel.config.js文件 配置presets预设 和plugins 插件
-
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规则的修改
-
react项目的配置
- @babel/preset-react @babel/plugin-proposal-class-properties @babel/plugin-proposal-decorators @babel/plugin-syntax-dynamic-import等
7.常见的一些优化
- 减少文件的搜索访问 resolve alias exclude mainFields
- module.noParse不需要递归解析此模块(ele的UI框架)
- dll动态链接库(代码块)将基础模块打包出来到单独的动态链接库中在需要导入的时候直接到连接库中webpack.dll.config.js
- 多线程 happypack webpack-parallel-uglify-plugin(js多线程压缩)
- cdn 静态资源放在cdn服务器上(注意pubilcPath的配置)
-
提取公共代码,代码分离
- 入口的起点分离 entry分割
- 懒加载 import在webpack就是个天然的分割器 使用jsonp形式加载的
- 基础类库 长期缓存
- 页面之间的公用代码
- 配置optimization:中的splitChunks(分割代码)
- tree shaking剔除无用的死代码作用域等
8.其他一些配置
- 懒加载 import npm install @babel/plugin-syntax-dynamic-import
- resolve的配置 extensions扩展 alias别名配置
- devtool source-map文件 源码映射 定位错误
- devServer 这个配置很重要
- 区分不同环境的配置 cross-env 定义环境变量 webpack-merge做配置的合并
9.vue-cli2升级webpack的过程
- 安装最新的webpack webpck-cli webpack-dev-server
- 更新一些loader plugin eslint babel的升级使用自动升级工具
- webpack相关的 npm install --save-dev webpack@latest webpack-cli webpack-dev-server@latest webpack-dev-middleware@latest webpack-bundle-analyzer@latest webpack-merge@latest
- 一些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
- 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
- vue相关的升级npm install --save-dev vue-template-compiler@latest vue-loader@latest vue-style-loader@latest
- babel的升级npx babel-upgrade --write --install
- mode: 'development'的修改
- 删除一些内置的插件 例如webpack.NamedModulesPlugin webpack.NoEmitOnErrorsPlugin
- 引入const { VueLoaderPlugin } = require('vue-loader')
- 使用mini-css-extract-plugin 替代extract-text-webpack-plugin
- 代码分割 将new webpack.optimize改为 optimization: {splitChunks: {}}来配置
10.babel相关
- astexplorer.net/ 获取代码对应的ast结构
- @babel/core babel核心库 用来实现核心的编译
- @babel/types实现类型的判断 生成ast零部件
- 使用js parser esprima (webpack使用的是acorn)
11.自定义loader
- loader就是暴露出一个function出去 source作为参数
- 最后的loader最早调用 传入原始的资源
- 异步 async 缓存等
- 实现一个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
- 插件是webpack的一等公民(明确监听的事件 触发的钩子函数)
- 两个核心概念 compiler和compilation
- compiler对象代表了完整的webpack环境配置 这个对象在启动webpack被一次建立 配置好可操作的设置 在webpack应用一个插件事 接收一个compiler对象的引用 可以用来访问webpack的主环境
- compilation对象代表了一次资源版本构建 运行webpack中间件时 每当检测到一个文件的变化 就会创建一个compilation 生成一组新的编译资源 compilation对象提供了很多关键时机的回调 供插件自定义处理使用
- 插件需要实现一个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 复制代码
- 常见的钩子 不同的阶段
-
初始化阶段
- 从配置文件和shell语句读取和配置参数得到最终的参数
- 初始化compiler 全局只有一个compiler 该实例包含了完整的webpack配置 负责文件监听和启动配置
- 加载插件 依次调用插件的apply方法 让插件监听事件节点
- 给插件传入compiler实例的引用 方便调用webpack提供的api
- entry-option 读取配置的entry实例化对应的entryplugin为递归解析做准备
- after-plugin 调用完所有内置和配置插件的apply方法
- after-resolvers 根据配置初始化resolver 负责在文件系统中寻找指定路径的文件
-
编译阶段
- run 启动一次新的编译
- watch-run 监听模式的编译
- compile 告诉插件一次新的编译要启动
- compilation 每次检测到文件变化 一个新的compilation被创建
- make 从entry开始读取文件 根据不同文件使用对应的loader做编译 递归
- after-compiler 一次compilation执行完成
- 在compilation还有很多消失件 build-module normal-module-loader program seal
-
输出阶段
- should-emit 需要输出的文件准备好
- emit 确定要输出的文件
- after-emit 文件输出完成
- failed 在编译和输出遇到异常就会退出 直接到failed 可以获取到具体的出错原因
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- TiDB入门(四):从入门到“跑路”
- MyBatis从入门到精通(一):MyBatis入门
- MyBatis从入门到精通(一):MyBatis入门
- Docker入门(一)用hello world入门docker
- 赵童鞋带你入门PHP(六) ThinkPHP框架入门
- 初学者入门 Golang 的学习型项目,go入门项目
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Learning Web App Development
Semmy Purewal / O'Reilly Media / 2014-3-3 / USD 29.99
Grasp the fundamentals of web application development by building a simple database-backed app from scratch, using HTML, JavaScript, and other open source tools. Through hands-on tutorials, this pract......一起来看看 《Learning Web App Development》 这本书的介绍吧!