webpack 的简单介绍(待完善)

2020/03/06 JavaScript

webpack

说一说 webpack 的概念,插件,loader,关于api的配置不说,可以去看文档或者

webpack 能够做什么

它做的事情是,分析你的项目结构,找到 JavaScript 模块以及其它的一些浏览器不能直接运行的拓展语言(ScssTypeScript 等),并将其打包为合适的格式以供浏览器使用

构建就是把源代码转换成发布到线上的可执行 JavaScripCSSHTML 代码,包括如下内容。

代码转换:TypeScript 编译成 JavaScriptSCSS 编译成 CSSloader

文件优化:压缩 JavaScriptCSSHTML 代码,压缩合并图片等。

代码分割:提取多个页面的公共代码、提取首屏不需要执行部分的代码让其异步加载。

模块合并:在采用模块化的项目里会有很多个模块和文件,需要构建功能把模块分类合并成一个文件。

自动刷新:监听本地源代码的变化,自动重新构建、刷新浏览器。

代码校验:在代码被提交到仓库前需要校验代码是否符合规范,以及单元测试是否通过。

自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统。

构建其实是工程化、自动化思想在前端开发中的体现,把一系列流程用代码去实现,让代码自动化地执行这一系列复杂的流程。 构建给前端开发注入了更大的活力,解放了我们的生产力。

weback 的 loader 怎么写

loader 从本质上来说其实就是一个 node 模块

单一原则:每一个人 loader 只做一件事,因为东西越小越好组合,越好维护

从右到左,链式执行,上一个 loader 的处理结果给笑一个接着处理

模块化: 每一个模块都是独立的,不依赖任何东西,一定的输入就有一定的输出

无状态

链式调用:webpack 会按照顺序链式调用每一个 loader

统一原则:遵循 webpack 制定的设计规则和结构,输入与输出均为字符串,各个 loader 完全独立,即插即用

  1. 在项目中安装了 webpackwebpack-cli

  2. 新建一个 webpack.config.js 文件

const path = require('path')
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  module: {
    rules: [{
      test: /\.js$/,
      loader: path.resolve(__dirname, 'src', 'loaders', 'log-loader')// 这个就是我们自己的写的loader所在的目录
    }]
  }
}
  1. 分别建几个目录 src/base.js,src/index.js,src/loaders/log-loader
module.exports = 'sunseekers' // base.js
const name = require('./base') // index.js

// loaders/log-loader
module.exports = function (sourse) {
  console.log('在webpack里面配置了一个rules,现在所有js文件都会进过一个loader文件,进行处理,这里进过的是我们自己建的一个loader文件,sourse是文件的原内容。这个日志会在build的时候看到这一句话');
  return sourse
}
  1. 配置 webpack 的命令,在 package.json
{
  "name": "webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack --mode production"// 主要是这一句话
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack-cli": "^3.3.11",
    "webpack": "^4.3.0"
  }
}

html loader

关于 loader 具体的写法的使用可以查看文档,或者通过 console.log 来查看日志 loader API

file-loader 是解析图片地址,把图片从源位置拷贝到目标位置并且修改原引用地址

url-loader 可以在文件比较小的时候,直接变成base64字符串内嵌到页面中

weback 的 plugin 怎么写

插件向第三方开发者提供了 webpack 引擎中完整的能力。使用阶段式的构建回调,开发者可以引入它们自己的行为到 webpack 构建流程中。创建插件比创建 loader 更加高级,因为你将需要理解一些 webpack 底层的内部特性来做相应的钩子

webpack 基础配置无法满足需求

插件几乎能够任意更改 webpack 编译结果这里才是我们写插件最重要的原因,输出我们想要的结果

webpack 内部也是通过大量内部插件实现的

plugin 的写法比 loader 要难很多,需要我们对 webpack 的生命周期有一定的了解,了解他内置的一些属性和方法。比如 compiler 对象代表了完整的 webpack 环境配置,只有构建一次,最重要的。compilation 代表每一次资源版本的构建每一次我们修改代码更新的时候都会构建一次

  1. 在配置文件中使用自己写的插件 webpack.config.js
const path = require('path')
const FilePlugin = require('./src/plugins/filename') // 自己插件地址
module.exports = {
  entry: "./src/index.js",
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
  },
  plugins: [
    new FilePlugin({
      filename: "file.list.md"
    })
  ]
  }
}
  1. 开始写插件 a. 插件是一 javaScript 命名函数 b. 在函数身上定义一个 apply 方法,处理内部实例自身的时间钩子函数 c. 功能完成之后调用 webpack 提供的回调 ``` // 生成一个新的md文档,里面放着所有的文件名 class FilesPlugin { constructor(options) { this.options = options } apply(compiler) { // compiler 要启动一次新的编译 // 你在哪监听这个事件 compiler.hooks.emit.tapAsync(“EmitPlugin”, (compilation, callback) => { // 这里就是我们需要了解 webpack 的生命周期和内部一些api的执行 console.log(‘看看静态资源是什么格式 :’,compilation.assets); let content = ## 文件列表\n\n const assets = compilation.assets for (let path in assets) { content += -- ${path}\n\n } compilation.assets[this.options.filename || ‘filelist.md’] = { source() { return content }, size() { return Buffer.byteLength(content) } } callback() })

} } module.exports = FilesPlugin ```

简简单说说

上面都是一些很简单的例子,只说告诉你怎么写,我们用的哪些插件远远比这些都要复杂的多,有些插件需要我们对 ast 有一定的了解。看了一段时间的 webpack ,我发现,要学习他们底层的源码或者知道一个东西是怎么写的,首先你要对他的流程特别清除,然后按部就班的写。我们平时调用的 jsapi 也是一样的。你知道 api 怎么用,有哪些参数,返回什么,这个函数做了一些什么。有了这样的理解思路会好很多,写起来就没有那么的难了。

先折叠无关的分支的逻辑,只看主体流程代码

寻找关键路径,根据变量名和方法名猜测意图,然后通过阅读源码来验证想法

debugger关键路径,理解整个执行过程

如何面对技术?

热爱研究技术当然是每一个技术人员需要具备的品质,阅读源码也是技术人员必须具备的一种能力。但是笔者更倾向于带着问题去研究技术,用技术手段去解决业务的痛点,技术是解决问题的工具,而不是结果或者目的。

不断挑战自己,拓展边界 很多时候人容易陷入舒适区,更愿意守着自己的领域做着自己特别擅长的事情。可能就是每天不断地完成不同需求的页面开发,然而实际上只是大量的重复劳动,并没有那么多的成长。多了解其他人在做什么,怎么做,遇到困难的技术场景就去挑战它而不是退缩。对于大量的重复劳动去更多的思考共性,怎么样才能把自己从这些事情中解放出来,有更多的时间去解决更多业务上的痛点以及技术难点。

技术是工具,也是赋能商业的手段,而不是目的 很多刚毕业的技术同学会陷入一种误区,认为把某个框架或者某些技术的实现细节或者实现原理吃透就能成长为技术大牛,或者是为了用某个技术或者某个框架而去做技术选型或者凭空实现一些很虚幻实际上并不能产生价值的功能。热爱研究技术当然是每一个技术人员需要具备的品质,阅读源码也是技术人员必须具备的一种能力。但是笔者更倾向于带着问题去研究技术,用技术手段去解决业务的痛点,技术是解决问题的工具,而不是结果或者目的。

如何汇报问题?

承认问题、分析原因、给出解决方案

尤其是在互联网行业,码农、产品经理、运营等岗位的领导者,他们往往能很好地跨部门沟通合作,向全公司展示业务成果。面对问题和成绩,都能够用得体的表达让老板信服。

会说话,也是职场人关键的自我修养。只会埋头钻研技能,就会丧失很多机会。

最让人难受的是,其实这些原因和解决方案我也想得到!但为什么,我就不能立马说上来呢?

不得不承认,嘴上功夫好的职场贱人,就是比闷头做事的自己更吃香!明明只做了两三件事,说起来像是做了十件事!

问题-原因-解决方案

第一个看到问题的人,就要立刻着手解决,不要拖延。

太多的人浪费了太多时间,为那些已经做出的决定。 投资回报率。把这个概念映射到学习上,就是,投入大量的时间,从源码中获得知识的回报。

好的学习过程,就是要反复提问。经过自己的思考,确实短时间内想不通,那提问就是最正确的选择。提问不会证明任何东西,证明不了你学习没认真,也证明不了你学习能力弱,更证明不了你就很菜。这中间所有的障碍,都只是我们自己给自己设置的限制而已。

问题无高低,问道有先后。

我们需要阅读源码吗?

什么时候看源码:我认为你至少已经对这个开源项目的使用已经很熟练了,并且对它的设计思想,用来解决什么问题等等都比较清楚的时候,为了进一步对它深入学习,就可以来看它的源码实现了。

以 Vue.js 为例,我们知道了它的核心思想是数据驱动 + 组件化,那么我们就可以问自己,Vue 模板的数据是如何渲染到 DOM 上的,数据更新后模板是如何重新渲染的,组件化是如何实现的,模板到 render 函数如何编译的等等。那么每一个问题都可以值得我们针对性地去学习源码。问题驱动的方式和坑驱动不同的地方在于这个学习过程是主动的,自驱的,学到的东西会更加系统和全面;而坑驱动往往都会满足于解决某个问题就停下了,学习会比较局限。

如何建立知识体系

建立知识架构

文法 词法。 编译原理的划分 语法 词法中有各种直接量、关键字、运算符,语法和语义则是表达式、语 句、函数、对象、模块 语义

运行时 类型 数据结构 执行过程 算法 类型则包含了对象、数字、字符串等……

学习的过程,实际上就是知识架构不断进化的过程,通过知识架构的自然延伸,我们可以更轻松地记忆一些原本难以记住的点,还可以发现被忽视的知识盲点

有一些知识,背后有一个很大的体系

:你要试着建立自己的知识架构,除此之外,还要学会追本溯源,找到知识的源头

类的概念:运行时没有改变

很多情况下 class 都可以替换 function

只关注输入和输出,中间的过程不管,封装起来

先看 generator 然后更加容易理解 async await

协程不是被操作系统内核所管理的,而是完全由程序所控制,性能得到了很大的提升,不会像线程切换那样消耗资源

async 是一个通过异步执行并隐式返回 Promise 作为结果的函数。


有时候,虽然素未谋面。却已相识很久,很微妙也很知足。在逝去的岁月里,我们在某一刻,共同经历着一样的情愫。

如果喜欢我的话,我们可以互相关注,相互学习的哟!互相鼓励,你的关注是我最大的动力来源

sunseekers

Search

    Table of Contents