webpack4 基础????
栏目: JavaScript · 发布时间: 5年前
内容简介:假期没有出去玩,但是我觉得很充实吼/(ㄒoㄒ)/~~根据Sean在 frontend masters上的课程加上个人的理解 Sean 是 webpack 的核心贡献者哦:hushed:这里应该是说所有代码写在一起,不是按照模块组织最后打包出一个文件来的。
假期没有出去玩,但是我觉得很充实吼/(ㄒoㄒ)/~~
根据Sean在 frontend masters上的课程加上个人的理解 Sean 是 webpack 的核心贡献者哦:hushed: 课程代码
为什么要使用webpack
传统方法在浏览器中执行JS
-
一个功能加载一个script 标签 e.g.
Jquery
,Swiper
- 加载一个巨大的JS文件。
script标签加载的弊端
- 扩展性太差,标签很多的情况下维持标签的顺序很痛苦。
- 全局变量污染
- 加载过多的JS文件有加载性能问题,因为浏览器的并行连接数有限制。可以参考 html - Max parallel http connections in a browser? - Stack Overflow
单独一个JS文件的弊端
这里应该是说所有代码写在一起,不是按照模块组织最后打包出一个文件来的。
- 不同功能的作用域问题
- 用户需要加载的文件过大。
- 维护性和可读性很差。
立即执行函数IIFEs
Immediately invoked function expressions
var outerScope = 1; const whatever = (function(dataNowUsedInside) { var outerScope = 4; return { someAttribute: "you want" }; })(1); console.log(outerScope); //1 复制代码
立即执行函数可以解决作用域冲突的问题,如上因为函数作用域的存在不会污染外部作用域。 PS: 另外上面的这个暴露出一个模块的模式叫 Revealing Module pattern 可以参考 Learning JavaScript Design Patterns
Make
, Gulp
, Grunt
, Broccoli
, Brunch
这些 工具 通过一个文件当做一个立即执行函数,将这些立即执行函数连接起来打包成一个文件。
这些工具的弊端:
- 每次更改一个文件都要重新构建所有文件
-
无法剔除没有使用过的代码,比如引入
Lodash
, 就用了几个函数,结果500Kb的文件都被引入了。 - 立即执行函数过多的话可能会造成性能问题。 参考这篇文章 The cost of small modules | Read the Tea Leaves 。文章里提到一个是函数内嵌套函数,还有在关联数组中查看模块在模块越来越多的情况下会暴露出意外的性能问题。另外立即执行函数会导致引擎立刻解析函数 (eager parse),大量的立即执行函数也会导致应用解析变慢。
- 没法做懒加载。
Javascript模块优缺点
CommonJS
node
里没有 <script>
标签,怎么加载JS代码呢,于是出来了CommonJS.
- 但是 CommonJS 不支持浏览器
- 没有动态绑定,什么是动态绑定可以参考深入es module
- CommonJS解析算法慢,因为它是同步的
- 没有静态分析,没法剔除无用代码
打包器
开发者不愿意从某个库的网上下载JS文件然后放到项目中来,他们想通过NPM分享模块代码。但是NPM上的是CommonJs模块的,所以就出现了 Browserify
之类的工具把CommonJS风格的代码解析 require
声明,按照你引用的顺序打包成浏览器可以执行的代码。
AMD
除了CommonJS还有很多模块加载模式。甚至还有AMD+CommonJS的模块加载模式。
没有真正的模块系统,没有node 浏览器都支持的。直到 ESM
的出现。
ESM
ES2015和模块是独立的两个部分。模块标准原名是 harmony modules specification 。你甚至可以用ES3的语法搭配模块使用。 ESM的问题:
- node 中的ESM尚未实现。
- 兼容问题。
webpack 能做什么
webpack 是一个模块打包器
- 库的作者使用他们喜欢的模块系统,AMD, CommonJS, webpack 可以让你使用任何的模块格式甚至混合,将它们最终打包成浏览器可以执行的代码。
- 在构建阶段创建动态打包模块(懒加载的模块)
- 不仅打包JS资源还包括html, css甚至图片
调试webpack
- 按照调试node的方法
node --inspect --inspect-brk ./node_modules/webpack/bin/webpack.js 复制代码
之后在浏览器中打开,可以参考debugger 2. 利用vscode
"configurations": [ { "type": "node", "request": "launch", "name": "webpack", "program": "${workspaceFolder}/node_modules/webpack/bin/webpack.js" } ] 复制代码
可以参考下debugging-webpack
webpack 基础概念
什么是依赖图(dependency graph)
webpack根据模块之间的依赖关系递归构建而成dependency-graph
entry
告诉webpack从那个文件开始构建它的依赖图。webpack4默认配置是 src/index.js
output
告诉webpack打包好的文件的位置名称等。webpack4默认配置会打包到 dist/main.js
loader
webpack开箱只理解js和json文件。loader可以将其他模块加载进来转换成js 模块,然后加载到依赖图里。webpack默认使用的是 acorn 解析js文件,acorn默认只会处理stage4的提案。所以比较新的特性webpack是处理不了的,这个时候可以借助babel 这里举两个loader
babel-loader
module: { rules: [ { test: /\.js$/, exclude: /node_modules/, use: { loader: 'babel-loader', options: { presets: ['@babel/preset-env'] } } } ] } 复制代码
babel-loader8.x需要配合使用的是@babel-core以及@babel/preset-env
npm install -D babel-loader @babel/core @babel/preset-env 复制代码
babel-loader:webpack和babel之间的桥梁 @babel/core: 解析文件并且生成文件 @babel/preset-env: 相应的转换规则
css loader
npm install -D css-loader style-loader 复制代码
{ test: /\.css$/, loaders: ['style-loader', 'css-loader'] } 复制代码
loader解析顺序是从右向左可以 可以理解成这样 styleLoader(cssLoader())
一个方法的输出是另一个方法的参数。 css-loader:
负责将css文件转换成js style-loader:
将css内容插入 <style>
标签中 ps:我在安装了相关loader之后, 在vscode里去尝试从node_modules目录里找发现怎么也找不到相关loader o(╯□╰)o,最后我直接打开了文件目录找到了。。。
如何写一个loader
write-a-loader 总结下就是loader是一个函数,在webpack配置里可以配置loader的别名,以及你自己写的loader的解析位置。 函数的参数就是上一个loader处理好后的字符串。loader也分同步和异步的,babel-loader就是异步的。
plugin
plugin可以在webpack的构建的任意时刻执行一些特定任务,比如打包优化,插入环境变量等。 webpack源码有很大部分都是插件写的,具体会再出一篇详细讲下webpack是如何工作的,这里就简单介绍下。
如何写一个插件
class myFirstWebpackPlugin { apply(compiler){ compiler.hooks.done.tap('myFirstWebpackPlugin',(stats)=>{ }) } } module.exports = myFirstWebpackPlugin 复制代码
插件可以在webpack构建的任意时刻执行,和钩子函数一样,提前在这些时间点注册回调函数,插件的钩子同样可以是同步或者异步的。上面的实例是在构建完成后执行,回调函数的参数里包括一系列统计数据,构建开始时间结束时间等。
webpack代码拆分(code splitting)
代码拆分的用途:
- 不需要在首屏加载的比较大的第三方库比如three.js
- 模态框提示框等用户可能不会去点击的
- 路由组件
代码拆分的好处:
- 提升首屏加载速度,提升用户体验特别是移动端
- 有助于提升SEO,google会降低加载慢的网站的权重
webpack会将 import()
引用的模块打包到单独打包到输出目录下,webpack内置的 acorn
解析器默认是只解析stage4的, import()
仍然在stage3, proposals
。这是因为webpack引用了 acorn-dynamic-import
可以支持在不使用babel的情况下解析 import()
语法。如果项目中使用了 babel-loader
需要再配置 @babel/plugin-syntax-dynamic-import
,否则babel会报错,因为babel也是需要将代码解析转换成抽象语法树的。
webpack代码拆分分为静态和动态代码拆分,但是无论哪种,都是将异步请求的模块提前打包到输出目录中。
静态代码拆分(static code splitting)
// main.js const getFooter = () => import('./footer'); button.addEventListener('click',e=>{ getFooter().then(m=>{ document.body.appendChild(m.footer) }) }) // footer.js const footer = document.createElement("footer"); export { footer }; 复制代码
import()
返回的是一个 promise
动态代码拆分(dynamic code splitting)
const setButtonStyle = color => import(`./button-style/${color}`); 复制代码
上面的 ./button-style
是部分地址,webpack会将这个地址下面的js模块进行单独打包。这个可以用在当这个目录下有很多文件需要代码拆分的时候。
魔法注释(magic comment)
内联注释控制webpack动态打包行为,为什么要使用它?因为这样不会增加新语法,不和动态import以及 loader 规范冲突。
import( /* webpackMode: "lazy-once" */ `./button-style/${color}`); 复制代码
比如上面这个 webpackMode
默认是 lazy
它会将 ./button-style
下的所有模块都单独打包; lazy-once
则会将其下面的所有模块打成一个包常用于开发环境减少打包次数。
更多注释选项请参考官网magic-comments
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First Rails
David Griffiths / O'Reilly Media / 2008-12-30 / USD 49.99
Figure its about time that you hop on the Ruby on Rails bandwagon? You've heard that it'll increase your productivity exponentially, and allow you to created full fledged web applications with minimal......一起来看看 《Head First Rails》 这本书的介绍吧!