整合營銷服務(wù)商

          電腦端+手機(jī)端+微信端=數(shù)據(jù)同步管理

          免費(fèi)咨詢熱線:

          如何寫一個webpack插件(一)

          如何寫一個webpack插件(一)

          最近由于用著html-webpack-plugin覺得很不爽,于是乎想自己動手寫一個插件。原以為像gulp插件一樣半天上手一天寫完,但令人郁悶的是完全找不到相關(guān)的文章。一進(jìn)官方文檔卻是被嚇傻了。首先是進(jìn)入how to write a plugin看了一頁簡單的介紹。然后教程會告訴你,你需要去了解compiler和compilation這兩個對象,才能更好地寫webpack的插件,然后作者給了github的鏈接給你,讓你去看源代碼,我暈。不過幸好最后給了一個plugins的API文檔,才讓我開發(fā)的過程中稍微有點(diǎn)頭緒。

          how to write a plugin這個教程還是可以好好看看的,尤其是那個simple example,它會教你在compilation的emit事件或之前,將你需要生成的文件放到webpack的compilation.assets里,這樣就可以借助webpack的力量幫你生成文件,而不需要自己手動去寫fs.writeFileSync。

          主要就是這段代碼

          compilation.assets['filelist.md']={
                source: function {
                  return filelist;
                },
                size: function {
                  return filelist.length;
                }
          };

          基本特性介紹

          首先,定義一個函數(shù)func,用戶設(shè)置的options基本就在這里處理。

          其次,需要設(shè)一個func.prototype.apply函數(shù)。這個函數(shù)是提供給webpack運(yùn)行時(shí)調(diào)用的。webpack會在這里注入compiler對象。

          輸出complier對象,你會看到這一長串的內(nèi)容,初步一看,我看出了兩大類(有補(bǔ)充的可以告訴我)。一個webpack運(yùn)行時(shí)的參數(shù),例如_plugins,這些數(shù)組里的函數(shù)應(yīng)該是webpack內(nèi)置的函數(shù),用于在compiltion,this-compilation和should-emit事件觸發(fā)時(shí)調(diào)用的。另一個是用戶寫在webpack.config.js里的參數(shù)。隱約覺得這里好多未來都可能會是webpack暴露給用戶的接口,使webpack的定制化功能更強(qiáng)大。

          Compiler {
            _plugins:
             { compilation: [ [Function], [Function], [Function], [Function] ],
               'this-compilation': [ [Function: bound ] ],
               'should-emit': [ [Function] ] },
            outputPath: '',
            outputFileSystem: null,
            inputFileSystem: null,
            recordsInputPath: null,
            recordsOutputPath: null,
            records: {},
            fileTimestamps: {},
            contextTimestamps: {},
            resolvers:
             { normal: Tapable { _plugins: {}, fileSystem: null },
               loader: Tapable { _plugins: {}, fileSystem: null },
               context: Tapable { _plugins: {}, fileSystem: null } },
            parser:
             Parser {
               _plugins:
                { 'evaluate Literal': [Object],
                  'evaluate LogicalExpression': [Object],
                  'evaluate BinaryExpression': [Object],
                  'evaluate UnaryExpression': [Object],
                  'evaluate typeof undefined': [Object],
                  'evaluate Identifier': [Object],
                  'evaluate MemberExpression': [Object],
                  'evaluate CallExpression': [Object],
                  'evaluate CallExpression .replace': [Object],
                  'evaluate CallExpression .substr': [Object],
                  'evaluate CallExpression .substring': [Object],
                  'evaluate CallExpression .split': [Object],
                  'evaluate ConditionalExpression': [Object],
                  'evaluate ArrayExpression': [Object],
                  'expression Spinner': [Object],
                  'expression ScreenMod': [Object] },
               options: undefined },
            options:
             { entry:
                { 
                  'index': '/Users/mac/web/src/page/index/main.js' },
               output:
                { publicPath: '/homework/features/model/',
                  path: '/Users/mac/web/dist',
                  filename: 'js/[name].js',
                  libraryTarget: 'var',
                  sourceMapFilename: '[file].map[query]',
                  hotUpdateChunkFilename: '[id].[hash].hot-update.js',
                  hotUpdateMainFilename: '[hash].hot-update.json',
                  crossOriginLoading: false,
                  hashFunction: 'md5',
                  hashDigest: 'hex',
                  hashDigestLength: 20,
                  sourcePrefix: '\t',
                  devtoolLineToLine: false },
               externals: { react: 'React' },
               module:
                { loaders: [Object],
                  unknownContextRequest: '.',
                  unknownContextRecursive: true,
                  unknownContextRegExp: /^\.\/.*$/,
                  unknownContextCritical: true,
                  exprContextRequest: '.',
                  exprContextRegExp: /^\.\/.*$/,
                  exprContextRecursive: true,
                  exprContextCritical: true,
                  wrappedContextRegExp: /.*/,
                  wrappedContextRecursive: true,
                  wrappedContextCritical: false },
               resolve:
                { extensions: [Object],
                  alias: [Object],
                  fastUnsafe: ,
                  packageAlias: 'browser',
                  modulesDirectories: [Object],
                  packageMains: [Object] },
               plugins:
                [ [Object],
                  [Object],
                  [Object],
                  [Object],
                  NoErrorsPlugin {},
                  [Object],
                  [Object] ],
               devServer: { port: 8081, contentBase: './dist' },
               context: '/Users/mac/web/',
               watch: true,
               debug: false,
               devtool: false,
               cache: true,
               target: 'web',
               node:
                { console: false,
                  process: true,
                  global: true,
                  setImmediate: true,
                  __filename: 'mock',
                  __dirname: 'mock' },
               resolveLoader:
                { fastUnsafe: ,
                  alias: {},
                  modulesDirectories: [Object],
                  packageMains: [Object],
                  extensions: [Object],
                  moduleTemplates: [Object] },
               optimize: { occurenceOrderPreferEntry: true } },
            context: '/Users/mac/web/' }

          除此以外,compiler還有一些如run, watch-run的方法以及compilation, normal-module-factory對象。我目前用到的,主要是compilation。其它的等下一篇有機(jī)會再說。

          對比起compiler還有compiler.plugin函數(shù)。這個相當(dāng)于是插件可以進(jìn)行處理的webpack的運(yùn)行中的一些任務(wù)點(diǎn),webpack就是完成一個又一個任務(wù)而完成整個打包構(gòu)建過程的。如make是最開始的起點(diǎn), complie就是編譯任務(wù)點(diǎn),after-complie是編譯完成,emit是即將準(zhǔn)備生成文件,after-emit是生成文件之后等等,前面幾個都是比較生動形象的任務(wù)點(diǎn)。

          至于compilation,它繼承于compiler,所以能拿到一切compiler的內(nèi)容(所以你也會看到webpack的options),而且也有plugin函數(shù)來接入任務(wù)點(diǎn)。在compiler.plugin('emit')任務(wù)點(diǎn)輸出compilation,會得到大致下面的對象數(shù)據(jù),因?yàn)閷?shí)在太長,我只保留了最重要的assets部份:

          assetsCompilation {
            assets:
             { 'js/index/main.js':
                CachedSource {
                  _source: [Object],
                  _cachedSource: undefined,
                  _cachedSize: undefined,
                  _cachedMaps: {} } },
            errors: ,
            warnings: ,
            children: ,
            dependencyFactories:
             ArrayMap {
               keys:
                [ [Object],
                  [Function: MultiEntryDependency],
                  [Function: SingleEntryDependency],
                  [Function: LoaderDependency],
                  [Object],
                  [Function: ContextElementDependency],
               values:
                [ NullFactory {},
                  [Object],
                  NullFactory {} ] },
            dependencyTemplates:
             ArrayMap {
               keys:
                [ [Object],
                  [Object],
                  [Object] ],
               values:
                [ ConstDependencyTemplate {},
                  RequireIncludeDependencyTemplate {},
                  NullDependencyTemplate {},
                  RequireEnsureDependencyTemplate {},
                  ModuleDependencyTemplateAsRequireId {},
                  AMDRequireDependencyTemplate {},
                  ModuleDependencyTemplateAsRequireId {},
                  AMDRequireArrayDependencyTemplate {},
                  ContextDependencyTemplateAsRequireCall {},
                  AMDRequireDependencyTemplate {},
                  LocalModuleDependencyTemplate {},
                  ModuleDependencyTemplateAsId {},
                  ContextDependencyTemplateAsRequireCall {},
                  ModuleDependencyTemplateAsId {},
                  ContextDependencyTemplateAsId {},
                  RequireResolveHeaderDependencyTemplate {},
                  RequireHeaderDependencyTemplate {} ] },
            fileTimestamps: {},
            contextTimestamps: {},
            name: undefined,
            _currentPluginApply: undefined,
            fullHash: 'f4030c2aeb811dd6c345ea11a92f4f57',
            hash: 'f4030c2aeb811dd6c345',
            fileDependencies: [ '/Users/mac/web/src/js/index/main.js' ],
            contextDependencies: ,
            missingDependencies:  }

          assets部份重要是因?yàn)槿绻阆虢柚鷚ebpack幫你生成文件,你需要像官方教程how to write a plugin在assets上寫上對應(yīng)的文件信息。

          除此以外,compilation.getStats這個函數(shù)也相當(dāng)重要,能得到生產(chǎn)文件以及chunkhash的一些信息,如下:

          assets{ errors: ,
            warnings: ,
            version: '1.12.9',
            hash: '5a5c71cb2accb8970bc3',
            publicPath: 'xxxxxxxxxx',
            assetsByChunkName: { 'index/main': 'js/index/index-4c0c16.js' },
            assets:
             [ { name: 'js/index/index-4c0c16.js',
                 size: 453,
                 chunks: [Object],
                 chunkNames: [Object],
                 emitted: undefined } ],
            chunks:
             [ { id: 0,
                 rendered: true,
                 initial: true,
                 entry: true,
                 extraAsync: false,
                 size: 221,
                 names: [Object],
                 files: [Object],
                 hash: '4c0c16e8af4d497b90ad',
                 parents: ,
                 origins: [Object] } ],
            modules:
             [ { id: 0,
                 identifier: 'multi index/main',
                 name: 'multi index/main',
                 index: 0,
                 index2: 1,
                 size: 28,
                 cacheable: true,
                 built: true,
                 optional: false,
                 prefetched: false,
                 chunks: [Object],
                 assets: ,
                 issuer: null,
                 profile: undefined,
                 failed: false,
                 errors: 0,
                 warnings: 0,
                 reasons:  },
               { id: 1,
                 identifier: '/Users/mac/web/node_modules/babel-loader/index.js?presets=es2015&presets=react!/Users/mac/web/src/js/main/index.js',
                 name: './src/js/index/main.js',
                 index: 1,
                 index2: 0,
                 size: 193,
                 cacheable: true,
                 built: true,
                 optional: false,
                 prefetched: false,
                 chunks: [Object],
                 assets: ,
                 issuer: 'multi index/main',
                 profile: undefined,
                 failed: false,
                 errors: 0,
                 warnings: 0,
                 reasons: [Object],
                 source: ''  // 具體文件內(nèi)容}
           ],
            filteredModules: 0,
            children:  }

          這里的chunks數(shù)組里,是對應(yīng)會生成的文件,以及md5之后的文件名和路徑,里面還有文件對應(yīng)的chunkhash(每個文件不同,但如果你使用ExtractTextPlugin將css文件獨(dú)立出來的話,它會與require它的js入口文件共享相同的chunkhash),而assets.hash則是統(tǒng)一的hash,對每個文件都一樣。值得關(guān)注的是chunks里的每個文件,都有source這一項(xiàng)目,提供給開發(fā)者直接拿到源文件內(nèi)容(主要是js,如果是css且使用ExtractTextPlugin,則請自行打印出來參考)。

          例子

          接下來,會以最近我寫的一個插件html-res-webpack-plugin作為引子,來介紹基本的寫插件原理。插件的邏輯就寫在index.js里。

          首先,將用戶輸入的參數(shù)在定好的函數(shù)中處理,HtmlResWebpackPlugin。

          然后,新增apply函數(shù),在里面寫好插件需要切入的webpack任務(wù)點(diǎn)。目前HtmlResWebpackPlugin插件只用到emit這個任務(wù)點(diǎn),其它幾個僅作為演示。

          第三步,調(diào)用addFileToWebpackAsset方法,寫compilation.assets,借助webpack生成html文件。

          第四步,在開發(fā)模式下(isWatch=true),直接生成html,但在生產(chǎn)模式下(isWatch=true),插件會開始對靜態(tài)資源(js,css)進(jìn)行md5或者內(nèi)聯(lián)。

          第五步,調(diào)用findAssets方法是為了通過compilation.getStats拿到的數(shù)據(jù),去匹配對應(yīng)的靜態(tài)資源,還有找到對應(yīng)的哈希(是chunkhash還是hash)。

          最六步,調(diào)用addAssets方法,對靜態(tài)資源分別做內(nèi)聯(lián)或者md5文件處理。內(nèi)聯(lián)資源的函數(shù)是inlineRes,你會看到我使用了compilation.assets[hashFile].source 及 compilation.assets[hashFile].children[1]._value。前者是針對于js的,后者是針對使用了ExtractTextPlugin的css資源。

          最后一步,即是內(nèi)聯(lián)和md5完成后,再更新一下compilation.assets中對應(yīng)生成html的source內(nèi)容,才能正確地生成內(nèi)聯(lián)和md5后的內(nèi)容。

          后記

          有興趣可以試用一下html-res-webpack-plugin這個插件(為什么要寫一個新的html生成插件,我在readme里寫了,此處不贅述),看看有哪些用得不爽之處。目前只是第一版,還不適合用于生產(chǎn)環(huán)境。希望第二版的時(shí)候能適用于更多的場景,以及性能更好。到是,我也會寫第二篇插件開發(fā)文章,將本文還沒提到的地方一一補(bǔ)充完整。也歡迎大家在這里發(fā)貼,或者指出本人的謬誤之處。

          018 眼看就要過去了,今年的你相較去年技術(shù)上有怎樣的收獲呢?

          不論你是正在自學(xué)前端遇到了瓶頸,還是對某些技術(shù)熟練掌握但某些還未涉足,都希望這份清單能對你有所幫助。由于頭條不讓站外鏈接,可以自行復(fù)制來源鏈接或者文末查看更多

          作者:AlienZHOU

          來源:

          https://github.com/alienzhou/frontend-tech-list

          前端技術(shù)清單

          學(xué)習(xí)文章的知識往往是碎片化的。而前端涉及到的面很廣,這些知識如果不進(jìn)行有效梳理,則無法相互串聯(lián)、形成體系。因此,我結(jié)合工作體會將抽象出了一些前端基礎(chǔ)能力,并將看過、寫過的一些不錯的文章進(jìn)行整理,形成了一份(純)前端技術(shù)清單。

          不論你是正在自學(xué)前端,還是對前端某些技術(shù)熟練掌握但某些還未涉足,我都希望這份清單能幫助你 review 一些前端的基礎(chǔ)能力。

          0. 年度報(bào)告

          • 2018 前端工具調(diào)查報(bào)告
          • 2018 JavaScript 調(diào)查報(bào)告

          1. 基礎(chǔ)拾遺

          溫故而知新,不知則習(xí)之,是以牢固根基。

          1.1. JavaScript

          • You-Dont-Know-JS [英]
          • JavaScript 基礎(chǔ)運(yùn)行機(jī)制:
          • JS 引擎、運(yùn)行時(shí)與調(diào)用棧概述 [英]
          • V8 引擎簡介 [英]
          • 內(nèi)存管理與4中常見的泄漏 [英]
          • Event Loop(面試?yán)锟倳幸活} Event Loop…):
          • 從 Event Loop 規(guī)范探究 JavaScript 異步及瀏覽器更新渲染時(shí)機(jī)
          • 異步之 Event Loop [英]
          • NodeJS 中的 Event Loop、Timers 與 process.nextTick() [英]
          • Tasks、Microtasks、Queues 與Schedules [英]
          • Web Workers 及其5個常見使用場景 [英]
          • 如何避免 async/await 地獄 [英]
          • “回調(diào)地獄”的解決思路匯總

          1.2. CSS

          • You-Need-to-Know-CSS
          • CSS布局指南
          • 在 (S)CSS 中實(shí)現(xiàn)主題功能的 4? 種方法 [英]
          • CSS 中的各類換行處理方式 [英]:處理經(jīng)典的換行問題
          • 瀏覽器將rem轉(zhuǎn)成px時(shí)有精度誤差怎么辦?
          • 精準(zhǔn)操控的滾動體驗(yàn),淺談新標(biāo)準(zhǔn) Scroll Snap
          • 如何完美實(shí)現(xiàn)一個非button元素的按鈕 [英]
          • 巧用 CSS Grid 來創(chuàng)建橫向滾動容器 [英]
          • 如何處理內(nèi)聯(lián)元素中的空隙 [英]
          • CSS Stacking Context 里那些鮮為人知的坑

          1.3. 瀏覽器

          • 瀏覽器的工作原理
          • 現(xiàn)代瀏覽器內(nèi)部是如何運(yùn)行的:
          • Chrome瀏覽器概覽
          • 瀏覽時(shí)發(fā)生了什么?
          • 渲染進(jìn)程的內(nèi)部工作原理
          • compositor是如何來提高交互性能的?
          • 完整的頁面生命周期 API 介紹 [英]
          • 四個新的觀察者:Intersection / Mutation / Resize / Performance (Observer)
          • 渲染引擎工作方式及優(yōu)化建議 [英]
          • 瀏覽器內(nèi)核渲染:重建引擎
          • 跨域解決方案匯總

          2. 工程化與工具

          軟件規(guī)模的擴(kuò)大帶來了工程化的需求,前端也不例外。隨著 NodeJS 的出現(xiàn),前端工程師可以使用熟悉的 JS 快速開發(fā)所需的工具。工具鏈生態(tài)的繁榮也是前端圈繁榮的一個寫照。

          2.1. webpack

          • webpack 中的 Chunk 關(guān)系圖算法 [英]
          • webpack 進(jìn)階系列文章
          • 編譯優(yōu)化:
          • 如何提升大型項(xiàng)目中 webpack 的性能 [英]
          • 運(yùn)行時(shí)優(yōu)化:Separating a Manifest [英]
          • 在 webpack 中使用 <link rel=”prefetch/preload”> [英]
          • 如何更好使用 webpack tree-shaking
          • 關(guān)于 webpack 編譯緩存的討論:
          • mzgoddard's comment
          • [spec: webpack 5] - A module disk cache between build processes

          2.2. Gulp

          • Gulp 4 簡介 [英]
          • 基于Gulp的多頁面應(yīng)用實(shí)踐指南

          2.3. Linter

          • JS Linter 進(jìn)化史
          • 為何要在項(xiàng)目匯總使用 ESLint [英]

          2.4. 靜態(tài)類型(Typescript/Flow)

          • Typescript 總體架構(gòu) [英]
          • 為什么要在 JavaScript 中進(jìn)行靜態(tài)類型檢查:
          • 第一部分
          • 第二、三部分
          • 第四部分

          2.5. Babel

          • Babel 用戶手冊
          • Babel 插件手冊

          2.6. CSS預(yù)處理與模塊化

          • CSS 進(jìn)化史 [英]
          • CSS 模塊化方案系列

          3. 性能優(yōu)化

          性能優(yōu)化其實(shí)就是在理解瀏覽器的基礎(chǔ)上“因地制宜”,因此可以配合1.3節(jié)“瀏覽器”部分進(jìn)行理解。

          強(qiáng)烈推薦把 Google Web 上性能優(yōu)化 Tab 中的文章都通讀一遍,其基本涵蓋了現(xiàn)代瀏覽器中性能優(yōu)化的所有點(diǎn),非常系統(tǒng)。下面也摘錄了其中一些個人認(rèn)為非常不錯的篇幅。

          3.1. 加載性能

          • PRPL 模式 [英]
          • 圖片懶加載完全指南 [英]
          • 使用 Intersection Observer 來懶加載圖片 [英]
          • 圖片與視頻懶加載的詳細(xì)指南 [英]
          • 使用 Application Shell 架構(gòu)來實(shí)現(xiàn)秒開應(yīng)用 [英]

          3.2. 運(yùn)行時(shí)性能

          • 避免大型、復(fù)雜的布局和布局抖動 [英]
          • 什么導(dǎo)致強(qiáng)制同步布局(reflow)? [英]
          • 如何診斷強(qiáng)制同步布局 [英]
          • 無線性能優(yōu)化:Composite
          • 如何不擇手段提升scroll事件的性能
          • 使用 passive event listener 來提高滾動流暢性 [英]
          • 節(jié)流和去抖(throttle & debounce):
          • JavaScript 函數(shù)節(jié)流和函數(shù)去抖應(yīng)用場景辨析
          • underscore 函數(shù)去抖的實(shí)現(xiàn)
          • requestIdleCallback - 一個強(qiáng)大而神器的 API:
          • requestIdleCallback使用入門 [英]
          • Idle Until Urgent [英]:requestIdleCallback的妙用

          3.3. 前端緩存

          • Web 緩存簡介:以購買牛奶的為例 [英]
          • 大話前端緩存 [英]
          • 緩存(一)—— 緩存總覽:從性能優(yōu)化的角度看緩存
          • 緩存(二)—— 瀏覽器緩存機(jī)制:強(qiáng)緩存、協(xié)商緩存
          • 緩存(三)—— 數(shù)據(jù)存儲:cookie、Storage、indexedDB

          3.4. 性能調(diào)試與實(shí)踐

          • 使用 Chrome DevTools 提升頁面速度 [英]:Chrome DevTools實(shí)操講解
          • 了解 DevTools 中的 Resource Timing
          • 淘寶新勢力周H5性能優(yōu)化實(shí)戰(zhàn)
          • 優(yōu)化打包策略來提升頁面加載速度
          • Chrome DevTools 中你可能不知道的調(diào)試技巧
          • 前端性能測量 [英]

          3.5. 性能指標(biāo)

          • 以用戶為中心的前端性能指標(biāo) [英]:前端性能指標(biāo)的來龍去脈
          • DOMContentLoaded:
          • 你不知道的 DOMContentLoaded
          • Deciphering the Critical Rendering Path [英]
          • FP (First Paint):
          • Chrome的First Paint
          • FCP (First Contentful Paint):
          • First Contentful Paint Explained [英]
          • First Contentful Paint [英]
          • FMP (First Meaningful Paint):
          • Chrome 中的 First Meaningful Paint
          • Time to First Meaningful Paint
          • TTI (Time to interactive):
          • Time to Interactive Explainer
          • 衡量用戶體驗(yàn)的新標(biāo)準(zhǔn)
          • TTFB (Time To First Byte):
          • TTFB,以及頁面加載的時(shí)間節(jié)點(diǎn)
          • FID (First Input Delay):
          • First Input Delay
          • Speed Index:
          • WebPagetest: Speed Index

          4. 安全

          很多安全風(fēng)險(xiǎn)老生常談,但是往往到出現(xiàn)問題時(shí),才會被重視或者意識到。

          • 8大前端安全問題上篇
          • 8大前端安全問題下篇
          • 概念講解:編碼、加密、哈希與混淆 [英]
          • 常見 Web 安全攻防總結(jié)

          4.1. XSS

          • 如何防止XSS攻擊?

          4.2. CSRF

          • 如何防止CSRF攻擊?
          • Site Isolation [英]:Chrome的新特性

          4.3. CSP

          • Content Security Policy 入門教程
          • Content Security Policy (CSP) [英]

          4.4. HTTPS

          • 圖文還原 HTTPS 原理
          • 淺談有贊全站 HTTPS 推進(jìn)

          4.5. 安全實(shí)錄

          • About rel=noopener [英]:打開一個新頁面是如何帶來安全隱患的
          • 一種新型的“釣魚”方式 [英]
          • 一個媒體文件請求引發(fā)的跨站風(fēng)險(xiǎn) [英]
          • Mitigating Spectre [英]: Chrome 中的跨站安全問題

          5. 自動化測試

          自動化測試是軟件工程的重要部分之一,但卻極容易被忽視。

          • 2018 前端自動化測試綜述 [英]
          • 測試你的前端代碼(介紹篇)[英]

          5.1. 單元測試

          • 測試你的前端代碼(單元測試篇)[英]
          • Fakes、Mocks 以及 Stubs 概念明晰
          • 測試覆蓋(率)到底有什么用?

          5.2. 端到端測試 (E2E)

          • 測試你的前端代碼(E2E 測試篇)[英]
          • 什么是一個好的 E2E 測試?[英]
          • 平衡單元測試和端到端測試
          • 對過多的 E2E 測試說“不” [英]

          5.3. 其他

          • 測試你的前端代碼(集成測試篇)[英]
          • 測試你的前端代碼(可視化測試篇)[英]

          6. 框架與類庫

          如果說基礎(chǔ)知識是道,那框架與工具可能就是術(shù);學(xué)習(xí)與理解它們,但千萬不要成為它們的奴隸。

          6.1. React

          • React 底層揭秘 [英]
          • 你所需要知道的 React 細(xì)節(jié)
          • React Fiber 架構(gòu)
          • React 16 Fiber 源碼速覽
          • React 是怎樣煉成的:React早期的進(jìn)化之路
          • 從零開始實(shí)現(xiàn)一個React:
          • 1. JSX和虛擬DOM
          • 2. 組件和生命周期
          • 3. diff算法
          • 4. 異步的setState
          • 「react技術(shù)?!箚雾搼?yīng)用實(shí)踐快速入門

          6.2. Vue

          • 深入淺出 - vue變化偵測原理
          • Vue 模板編譯原理

          6.3. Redux

          • 重新設(shè)計(jì) Redux [英]:Rematch
          • 如何用 GraphQL 來替代 Redux [英]
          • 解讀 Redux 的設(shè)計(jì)思路與用法
          • (Redux)應(yīng)用構(gòu)建的三個原則 [英]

          6.4. RxJS

          • ReactiveX 官網(wǎng):寶石圖真的非常形象易讀
          • 響應(yīng)式編程,是明智的選擇
          • 圖解RxJS [英]
          • 調(diào)試RxJS:Tooling [英]
          • 調(diào)試RxJS:Logging [英]

          7. 新技術(shù)/方向

          前端領(lǐng)域新技術(shù)、新方向?qū)映霾桓F,這里匯總一些新技術(shù)方向;作為開發(fā)者需要多了解但是不要盲從

          7.1. PWA

          • PWA 學(xué)習(xí)與實(shí)踐系列
          • Service Worker 入門簡介 [英]
          • PWA 在 iOS 平臺上的特殊問題 [英]
          • 在你的 PWA 中小心使用 iOS 的 meta 標(biāo)簽 [英]
          • 餓了么的 PWA 升級實(shí)踐
          • 離線指南
          • Android 中的 WebAPKs [英]
          • Pinterest 的 PWA 實(shí)踐 [英]
          • 異步 HTTP Cookies API [英]:賦能Service Worker

          7.2. CSS Houdini

          • 認(rèn)識 Houdini 與 CSS Paint API [英]
          • 用 Houdini 來拯救 CSS Polyfill [英]

          7.3. Web Components

          • Web Components 基本概念和用法
          • Web Components 指南 [英]
          • Shadow DOM 使用簡介
          • HTMLUnknownElement 與 HTML5 自定義元素的故事

          7.4. 微前端(Micro Frontends)

          • 微前端主頁 [英]
          • 微前端的那些事兒
          • 技術(shù)雷達(dá)之「微前端」- 將微服務(wù)理念擴(kuò)展到前端開發(fā)

          7.5. HTTP/2

          • HTTP/2 幕后原理
          • 全面介紹的 HTTP/2 [英]
          • HTTP/2 主頁:
          • HTTP/2 協(xié)議 [英]
          • HPACK: HTTP/2 Header壓縮 [英]

          7.6. WebAssembly

          • WebAssembly 官網(wǎng)
          • WebAssembly 現(xiàn)狀與實(shí)戰(zhàn)
          • WebAssembly 系列:
          • 一、生動形象地介紹 WebAssembly
          • 二、JavaScript Just-in-time (JIT) 工作原理
          • 三、編譯器如何生成匯編
          • 四、WebAssembly 工作原理
          • 五、為什么 WebAssembly 更快?
          • 六、WebAssembly 的現(xiàn)在與未來

          8. 業(yè)務(wù)相關(guān)

          在業(yè)務(wù)中往往還有一些與“業(yè)務(wù)無關(guān)”的場景需求 —— 不論是什么業(yè)務(wù)幾乎都會遇到;因此,在變與不變中,我們更需要去抽象出這些問題。

          8.1. 數(shù)據(jù)打點(diǎn)上報(bào)

          • 如何精確統(tǒng)計(jì)頁面停留時(shí)長
          • 揭開JS無埋點(diǎn)技術(shù)的神秘面紗

          8.2. 前端監(jiān)控

          • 前端異常監(jiān)控解決方案研究
          • 監(jiān)控平臺前端SDK開發(fā)實(shí)踐
          • 把前端監(jiān)控做到極致
          • 前端監(jiān)控系統(tǒng)探索總結(jié)

          8.3. A/B測試

          • Twitter的A/B測試實(shí)踐:
          • 一、為什么要測試以及測試的意義
          • 二、技術(shù)概述
          • 三、檢測和避免 A/B Test中 bucket不平衡問題
          • 四、A/B Test中使用多個控制的啟示
          • Netflix A/B Test 實(shí)驗(yàn)平臺實(shí)踐 [英]
          • 指導(dǎo)方法
          • 實(shí)驗(yàn)中容易遇到的七種問題 [英]
          • 實(shí)驗(yàn)的七個準(zhǔn)則 [英]
          • 小流量如何進(jìn)行AB測試
          • 案例分享
          • 大眾點(diǎn)評AB測試框架Gemini
          • 新浪新聞客戶端AB測試與灰度發(fā)布
          • 天貓App A/B測試實(shí)踐
          • 工具
          • AB測試樣本數(shù)量計(jì)算器
          • AB測試結(jié)果有效性分析工具

          8.4. “服務(wù)端推”

          • 各類“服務(wù)器推”技術(shù)原理與實(shí)例
          • 長連接/websocket/SSE等主流服務(wù)器推送技術(shù)比較
          • Comet:基于 HTTP 長連接的“服務(wù)器推”技術(shù)
          • 深入 WebSockets、HTTP/2 SSE [英]
          • WebSocket 應(yīng)用安全問題分析

          8.5. 動效

          • 動畫設(shè)計(jì)的12個原則 [英]
          • 貝塞爾曲線掃盲
          • 動畫:從 AE 到 Web
          • 最全最好用的動效落地方法:
          • 基礎(chǔ)知識
          • 落地方式

          9. 不歸類的好文

          開卷有益。

          • Recursion? We don't need no stinking recursion!:如何將一些遞歸改為循環(huán)(尾遞歸優(yōu)化)
          • Turning your web traffic into a Super Computer:通過 Web Worker 和 WebSocket 來將全世界的電腦連接成超級計(jì)算機(jī)
          • Designing very large (JavaScript) applications:高屋建瓴,適合閱讀與思考

          程序開發(fā)過程中,我們始終要謹(jǐn)記的一點(diǎn)就是:程序是寫給人看的,不是寫給機(jī)器看的。任何項(xiàng)目開發(fā),都必須要考慮到人員迭代,我們不能讓下一個接手你代碼的人,在看到你寫的代碼時(shí)會說出這樣的話,“這個代碼是人寫出來的嗎?可讀性太差了”。因此,我們必須遵循一定的規(guī)范,讓代碼的可讀性更強(qiáng)。

          今天,我們就一起來看下前端開發(fā)過程所能涉及到的跟HTML有關(guān)的規(guī)范問題。

          HTML5

          文檔類型

          在HTML文件中,推薦使用支持HTML5特性的文檔聲明,<!DOCTYPE html>。

          命名規(guī)范

          首先是在文件的命名上,應(yīng)當(dāng)采用駝峰式命名,首字母小寫,后面每個單詞首字母大寫,而且對于具體的文件應(yīng)當(dāng)具有語義化,能夠給人一種直觀的感受這個文件的作用是什么?,F(xiàn)在前端開發(fā)開發(fā)過程中都講求模塊化開發(fā),甚至是組件化開發(fā),在文件命名時(shí)更應(yīng)該以模塊名或者組件名來命名。

          例如在寫一個AngularJS應(yīng)用時(shí),由于會涉及到Controller,Service,F(xiàn)ilter等概念,我們會分別建立一個文件,假如這個模塊的名字是庫存管理stockManage,我們可以這樣來命名文件。

          • stockManageCtrl

          • stockChangeService

          • stockChangeFilter

          語義化

          我們所說的語義化指的是使用具有語義化的標(biāo)簽,在H5中添加了類似于header, nav, article, section, aside, footer等標(biāo)簽,從單詞的意思上我們也很容易看出標(biāo)簽的含義。

          我們不推薦使用只有div標(biāo)簽的頁面,例如

          不推薦使用

          而是應(yīng)該使用以下這種帶有語義化的標(biāo)簽。

          推薦使用

          img標(biāo)簽

          img標(biāo)簽是網(wǎng)頁用來顯示照片的標(biāo)簽,在頁面所有標(biāo)簽中占據(jù)的比例非常之高,但是在使用img標(biāo)簽時(shí)也有下面需要注意的點(diǎn)。

          • 給定width和height屬性

          因?yàn)闉g覽器在加載圖片的過程中,需要先下載圖片,然后再解析圖片的高度和寬度,如果不給img元素設(shè)定高度和寬度,這樣在圖片加載過程中會不斷的計(jì)算,重排頁面的布局,在網(wǎng)絡(luò)不好的時(shí)候就會經(jīng)常出現(xiàn)元素出現(xiàn)不規(guī)律移動的情況。因此給img元素設(shè)定width和height屬性是必要的。

          • alt屬性

          img標(biāo)簽的alt屬性表示的是在圖片無法顯示時(shí),使用文字來代替顯示,它可以用在以下幾個場景中:

          1. 網(wǎng)路延遲太大

          2. src屬性指定路徑出錯

          3. 瀏覽器禁用圖像

          由于其有良好的信息提示效果,并且有助于網(wǎng)頁SEO效果,強(qiáng)烈建議在img標(biāo)簽中使用alt屬性

          而且很重要的一點(diǎn)是img標(biāo)簽的引入是需要呈現(xiàn)出與頁面相關(guān)的內(nèi)容,其他情況應(yīng)該使用CSS樣式實(shí)現(xiàn)。例如我們不推薦下面這種情況。

          不推薦

          而推薦使用下面這種情況

          推薦使用

          文件分離

          前端文件主要包括HTML頁面文件,CSS樣式文件和Javascript腳本文件。我們應(yīng)該讓三者各司其職,在HTML中不應(yīng)該出現(xiàn)CSS和JS表達(dá)式;在JS文件中,不應(yīng)該出現(xiàn)大量的HTML和CSS代碼。在HTML文檔中應(yīng)當(dāng)盡量少的引入CSS和JS文件。為了保證文件的純凈,我們應(yīng)當(dāng)遵循下面的原則。

          1. 一個HTML文件應(yīng)該只引入一個CSS文件

          2. 合理運(yùn)用JS合并技術(shù)(Gulp, Webpack插件),保證引入JS文件不多于兩個

          3. 不使用行內(nèi)腳本元素(<script>alert('Hello World')</script>)

          4. 不在標(biāo)簽上使用style內(nèi)聯(lián)樣式

          不要使用style屬性

          腳本加載

          腳本加載在網(wǎng)頁加載過程中是一個很耗性能的過程,如果把JS文件放在head標(biāo)簽里,它的加載會一直阻塞DOM的解析,造成頁面延遲。

          因此現(xiàn)在講求的是腳本的異步加載過程,我們會使用到async關(guān)鍵字,考慮到瀏覽器的兼容性,我們推薦使用下面的方式加載腳本。

          推薦方式

          合理使用ID和錨點(diǎn)

          合理使用ID和錨點(diǎn)可以非常方便的實(shí)現(xiàn)當(dāng)前頁面間的跳轉(zhuǎn),現(xiàn)在越來越多的教程網(wǎng)頁由于是單頁面,經(jīng)常會用到錨點(diǎn)跳轉(zhuǎn)。

          對錨點(diǎn)知識還不了解的,可以看看我寫的這篇文章《神奇的html錨點(diǎn),讓你的網(wǎng)頁在內(nèi)部自由的跳轉(zhuǎn)》。

          總結(jié)

          今天這篇文章主要總結(jié)了前端開發(fā)過程中的HTML規(guī)范問題,相信大家也或多或少遇到過,希望這篇文章能加深大家的認(rèn)識。


          主站蜘蛛池模板: 国产精品被窝福利一区| 国产在线精品观看一区| 中日韩精品无码一区二区三区| 肉色超薄丝袜脚交一区二区| 亚洲精品色播一区二区| 毛片无码一区二区三区a片视频| 99久久国产精品免费一区二区| 无码精品蜜桃一区二区三区WW| 国产精品无码一区二区三区电影 | 精品国产一区二区三区不卡| 人成精品视频三区二区一区 | 亚洲色偷精品一区二区三区| 国产一区二区三区在线电影| 亚洲欧美日韩国产精品一区| 日韩爆乳一区二区无码| 精品欧洲AV无码一区二区男男| 亚洲日本精品一区二区| 亚洲国产精品一区| 一夲道无码人妻精品一区二区| 亚洲一区二区影院| 国产成人久久精品区一区二区 | 日韩在线不卡免费视频一区| 精品无码av一区二区三区| 亚洲福利电影一区二区?| 久久久久人妻精品一区蜜桃| 久久国产精品视频一区| 97av麻豆蜜桃一区二区| 亚洲高清一区二区三区电影| 四虎成人精品一区二区免费网站| 精品无码日韩一区二区三区不卡| 亚洲一区二区三区国产精品无码 | 一本大道东京热无码一区 | 亚洲福利一区二区| 久久毛片一区二区| 无码人妻久久一区二区三区蜜桃| 免费国产在线精品一区| 久久精品国产一区二区| 麻豆文化传媒精品一区二区| 伊人久久大香线蕉av一区| 无码国产精品一区二区免费模式| 免费无码一区二区三区|