Vue 3.2 發布了,那尤雨溪是怎么發布 Vue.js 的?

1. 前言

大家好,我是若川。最近組織了源碼共讀活動,感興趣的可以加我微信 ruochuan12,長期交流學習。

之前寫的《學習源碼整體架構系列》 包含jQueryunderscorelodashvuexsentryaxiosreduxkoavue-devtoolsvuex4十篇源碼文章。

寫相對很難的源碼,耗費了自己的時間和精力,也沒收獲多少閱讀點贊,其實是一件挺受打擊的事情。從閱讀量和讀者受益方面來看,不能促進作者持續輸出文章。

所以轉變思路,寫一些相對通俗易懂的文章。其實源碼也不是想象的那么難,至少有很多看得懂

最近尤雨溪發布了3.2版本。小版本已經是3.2.4了。本文來學習下尤大是怎么發布vuejs的,學習源碼為自己所用。

本文涉及到的 vue-next/scripts/release.js文件,整個文件代碼行數雖然只有 200 余行,但非常值得我們學習。

歌德曾說:讀一本好書,就是在和高尚的人談話。同理可得:讀源碼,也算是和作者的一種學習交流的方式。

閱讀本文,你將學到:

1.?熟悉?vuejs?發布流程
2.?學會調試?nodejs?代碼
3.?動手優化公司項目發布流程

環境準備之前,我們先預覽下vuejs的發布流程。

vue 發布流程

2. 環境準備

打開 vue-next[1], 開源項目一般都能在 README.md 或者 .github/contributing.md[2] 找到貢獻指南。

而貢獻指南寫了很多關于參與項目開發的信息。比如怎么跑起來,項目目錄結構是怎樣的。怎么投入開發,需要哪些知識儲備等。

你需要確保 Node.js[3] 版本是 10+, 而且 yarn 的版本是 1.x Yarn 1.x[4]

你安裝的 Node.js 版本很可能是低于 10。最簡單的辦法就是去官網重新安裝。也可以使用 nvm等管理Node.js版本。

node?-v
#?v14.16.0
#?全局安裝?yarn
#?克隆項目
git?clone?https://github.com/vuejs/vue-next.git
cd?vue-next#?或者克隆我的項目
git?clone?https://github.com/lxchuan12/vue-next-analysis.git
cd?vue-next-analysis/vue-next#?安裝?yarn
npm?install?--global?yarn
#?安裝依賴
yarn?#?install?the?dependencies?of?the?project
#?yarn?release

2.1 嚴格校驗使用 yarn 安裝依賴

接著我們來看下 vue-next/package.json 文件。

//?vue-next/package.json
{"private":?true,"version":?"3.2.4","workspaces":?["packages/*"],"scripts":?{//?--dry?參數是我加的,如果你是調試?代碼也建議加//?不執行測試和編譯?、不執行?推送git等操作//?也就是說空跑,只是打印,后文再詳細講述"release":?"node?scripts/release.js?--dry","preinstall":?"node?./scripts/checkYarn.js",}
}

如果你嘗試使用 npm 安裝依賴,應該是會報錯的。為啥會報錯呢。因為 package.json 有個前置 preinstall ?node ./scripts/checkYarn.js 判斷強制要求是使用yarn安裝。

scripts/checkYarn.js文件如下,也就是在process.env環境變量中找執行路徑npm_execpath,如果不是yarn就輸出警告,且進程結束。

//?scripts/checkYarn.js
if?(!/yarn\.js$/.test(process.env.npm_execpath?||?''))?{console.warn('\u001b[33mThis?repository?requires?Yarn?1.x?for?scripts?to?work?properly.\u001b[39m\n')process.exit(1)
}

如果你想忽略這個前置的鉤子判斷,可以使用yarn --ignore-scripts 命令。也有后置的鉤子post。更多詳細的可以查看 npm 文檔[5]

2.2 調試 ?vue-next/scripts/release.js 文件

接著我們來學習如何調試 vue-next/scripts/release.js文件。

這里聲明下我的 VSCode 版本 是 1.59.0 應該 1.50.0 起就可以按以下步驟調試了。

code?-v
#?1.59.0

找到 vue-next/package.json 文件打開,然后在 scripts 上方,會有debug(調試)按鈕,點擊后,選擇 release。即可進入調試模式。

debugger

這時終端會如下圖所示,有 Debugger attached. 輸出。這時放張圖。

terminal

更多 nodejs 調試相關 ?可以查看官方文檔[6]

學會調試后,先大致走一遍流程,在關鍵地方多打上幾個斷點多走幾遍,就能猜測到源碼意圖了。

3 文件開頭的一些依賴引入和函數聲明

我們可以跟著斷點來,先看文件開頭的一些依賴引入和函數聲明

3.1 第一部分

//?vue-next/scripts/release.js
const?args?=?require('minimist')(process.argv.slice(2))
//?文件模塊
const?fs?=?require('fs')
//?路徑
const?path?=?require('path')
//?控制臺
const?chalk?=?require('chalk')
const?semver?=?require('semver')
const?currentVersion?=?require('../package.json').version
const?{?prompt?}?=?require('enquirer')//?執行子進程命令???簡單說?就是在終端命令行執行?命令
const?execa?=?require('execa')

通過依賴,我們可以在 node_modules 找到對應安裝的依賴。也可以找到其READMEgithub倉庫。

3.1.1 minimist ?命令行參數解析

minimist[7]

簡單說,這個庫,就是解析命令行參數的。看例子,我們比較容易看懂傳參和解析結果。

$?node?example/parse.js?-a?beep?-b?boop
{?_:?[],?a:?'beep',?b:?'boop'?}$?node?example/parse.js?-x?3?-y?4?-n5?-abc?--beep=boop?foo?bar?baz
{?_:?[?'foo',?'bar',?'baz'?],x:?3,y:?4,n:?5,a:?true,b:?true,c:?true,beep:?'boop'?}
const?args?=?require('minimist')(process.argv.slice(2))

其中process.argv的第一和第二個元素是Node可執行文件和被執行JavaScript文件的完全限定的文件系統路徑,無論你是否這樣輸入他們。

3.1.2 chalk 終端多色彩輸出

chalk[8]

簡單說,這個是用于終端顯示多色彩輸出。

3.1.3 semver ?語義化版本

semver[9]

語義化版本的nodejs實現,用于版本校驗比較等。關于語義化版本可以看這個語義化版本 2.0.0 文檔[10]

版本格式:主版本號.次版本號.修訂號,版本號遞增規則如下:
主版本號:當你做了不兼容的 API 修改,
次版本號:當你做了向下兼容的功能性新增,
修訂號:當你做了向下兼容的問題修正。
先行版本號及版本編譯信息可以加到“主版本號.次版本號.修訂號”的后面,作為延伸。

3.1.4 enquirer 交互式詢問 CLI

簡單說就是交互式詢問用戶輸入。

enquirer[11]

3.1.5 execa 執行命令

簡單說就是執行命令的,類似我們自己在終端輸入命令,比如 echo 若川

execa[12]

//?例子
const?execa?=?require('execa');(async?()?=>?{const?{stdout}?=?await?execa('echo',?['unicorns']);console.log(stdout);//=>?'unicorns'
})();

看完了第一部分,接著我們來看第二部分。

3.2 第二部分

//?vue-next/scripts/release.js//?對應?yarn?run?release?--preid=beta
//?beta
const?preId?=args.preid?||(semver.prerelease(currentVersion)?&&?semver.prerelease(currentVersion)[0])
//?對應?yarn?run?release?--dry
//?true
const?isDryRun?=?args.dry
//?對應?yarn?run?release?--skipTests
//?true?跳過測試
const?skipTests?=?args.skipTests
//?對應?yarn?run?release?--skipBuild?
//?true
const?skipBuild?=?args.skipBuild//?讀取?packages?文件夾,過濾掉?不是?.ts文件?結尾?并且不是?.?開頭的文件夾
const?packages?=?fs.readdirSync(path.resolve(__dirname,?'../packages')).filter(p?=>?!p.endsWith('.ts')?&&?!p.startsWith('.'))

第二部分相對簡單,繼續看第三部分。

3.3 第三部分

//?vue-next/scripts/release.js//?跳過的包
const?skippedPackages?=?[]//?版本遞增
const?versionIncrements?=?['patch','minor','major',...(preId???['prepatch',?'preminor',?'premajor',?'prerelease']?:?[])
]const?inc?=?i?=>?semver.inc(currentVersion,?i,?preId)

這一塊可能不是很好理解。inc是生成一個版本。更多可以查看semver文檔[13]

semver.inc('3.2.4',?'prerelease',?'beta')
//?3.2.5-beta.0

3.4 第四部分

第四部分聲明了一些執行腳本函數等

//?vue-next/scripts/release.js//?獲取?bin?命令
const?bin?=?name?=>?path.resolve(__dirname,?'../node_modules/.bin/'?+?name)
const?run?=?(bin,?args,?opts?=?{})?=>execa(bin,?args,?{?stdio:?'inherit',?...opts?})
const?dryRun?=?(bin,?args,?opts?=?{})?=>console.log(chalk.blue(`[dryrun]?${bin}?${args.join('?')}`),?opts)
const?runIfNotDry?=?isDryRun???dryRun?:?run//?獲取包的路徑
const?getPkgRoot?=?pkg?=>?path.resolve(__dirname,?'../packages/'?+?pkg)//?控制臺輸出
const?step?=?msg?=>?console.log(chalk.cyan(msg))

3.4.1 bin 函數

獲取 node_modules/.bin/ 目錄下的命令,整個文件就用了一次。

bin('jest')

相當于在命令終端,項目根目錄 運行 ./node_modules/.bin/jest 命令。

3.4.2 run、dryRun、runIfNotDry

const?run?=?(bin,?args,?opts?=?{})?=>execa(bin,?args,?{?stdio:?'inherit',?...opts?})
const?dryRun?=?(bin,?args,?opts?=?{})?=>console.log(chalk.blue(`[dryrun]?${bin}?${args.join('?')}`),?opts)
const?runIfNotDry?=?isDryRun???dryRun?:?run

run 真實在終端跑命令,比如 yarn build --release

dryRun 則是不跑,只是 console.log(); 打印 'yarn build --release'

runIfNotDry 如果不是空跑就執行命令。isDryRun 參數是通過控制臺輸入的。yarn run release --dry這樣就是truerunIfNotDry就是只是打印,不執行命令。這樣設計的好處在于,可以有時不想直接提交,要先看看執行命令的結果。不得不說,尤大就是會玩。

main 函數末尾,也可以看到類似的提示。可以用git diff先看看文件修改。

if?(isDryRun)?{console.log(`\nDry?run?finished?-?run?git?diff?to?see?package?changes.`)
}

看完了文件開頭的一些依賴引入和函數聲明等,我們接著來看main主入口函數。

4 main 主流程

第4節,主要都是main 函數拆解分析。

4.1 流程梳理 main 函數

const?chalk?=?require('chalk')
const?step?=?msg?=>?console.log(chalk.cyan(msg))
//?前面一堆依賴引入和函數定義等
async?function?main(){//?版本校驗//?run?tests?before?releasestep('\nRunning?tests...')//?update?all?package?versions?and?inter-dependenciesstep('\nUpdating?cross?dependencies...')//?build?all?packages?with?typesstep('\nBuilding?all?packages...')//?generate?changelogstep('\nCommitting?changes...')//?publish?packagesstep('\nPublishing?packages...')//?push?to?GitHubstep('\nPushing?to?GitHub...')
}main().catch(err?=>?{console.error(err)
})

上面的main函數省略了很多具體函數實現。接下來我們拆解 main 函數。

4.2 確認要發布的版本

第一段代碼雖然比較長,但是還好理解。主要就是確認要發布的版本。

調試時,我們看下這段的兩張截圖,就好理解啦。

終端輸出選擇版本號
終端輸入確認版本號
//?根據上文?mini?這句代碼意思是?yarn?run?release?3.2.4?
//?取到參數?3.2.4
let?targetVersion?=?args._[0]if?(!targetVersion)?{//?no?explicit?version,?offer?suggestionsconst?{?release?}?=?await?prompt({type:?'select',name:?'release',message:?'Select?release?type',choices:?versionIncrements.map(i?=>?`${i}?(${inc(i)})`).concat(['custom'])})//?選自定義if?(release?===?'custom')?{targetVersion?=?(await?prompt({type:?'input',name:?'version',message:?'Input?custom?version',initial:?currentVersion})).version}?else?{//?取到括號里的版本號targetVersion?=?release.match(/\((.*)\)/)[1]}
}//?校驗?版本是否符合?規范
if?(!semver.valid(targetVersion))?{throw?new?Error(`invalid?target?version:?${targetVersion}`)
}//?確認要?release
const?{?yes?}?=?await?prompt({type:?'confirm',name:?'yes',message:?`Releasing?v${targetVersion}.?Confirm?`
})//?false?直接返回
if?(!yes)?{return
}

4.3 執行測試用例

//?run?tests?before?release
step('\nRunning?tests...')
if?(!skipTests?&&?!isDryRun)?{await?run(bin('jest'),?['--clearCache'])await?run('yarn',?['test',?'--bail'])
}?else?{console.log(`(skipped)`)
}

4.4 更新所有包的版本號和內部 vue 相關依賴版本號

這一部分,就是更新根目錄下package.json 的版本號和所有 packages 的版本號。

//?update?all?package?versions?and?inter-dependencies
step('\nUpdating?cross?dependencies...')
updateVersions(targetVersion)
function?updateVersions(version)?{//?1.?update?root?package.jsonupdatePackage(path.resolve(__dirname,?'..'),?version)//?2.?update?all?packagespackages.forEach(p?=>?updatePackage(getPkgRoot(p),?version))
}

4.4.1 updatePackage 更新包的版本號

function?updatePackage(pkgRoot,?version)?{const?pkgPath?=?path.resolve(pkgRoot,?'package.json')const?pkg?=?JSON.parse(fs.readFileSync(pkgPath,?'utf-8'))pkg.version?=?versionupdateDeps(pkg,?'dependencies',?version)updateDeps(pkg,?'peerDependencies',?version)fs.writeFileSync(pkgPath,?JSON.stringify(pkg,?null,?2)?+?'\n')
}

主要就是三種修改。

1.?自己本身?package.json?的版本號
2.?packages.json?中?dependencies?中?vue?相關的依賴修改
3.?packages.json?中?peerDependencies?中?vue?相關的依賴修改

一圖勝千言。我們執行yarn release --drygit diff 查看的 git 修改,部分截圖如下。

更新的版本號舉例

4.4.2 updateDeps 更新內部 vue 相關依賴的版本號

function?updateDeps(pkg,?depType,?version)?{const?deps?=?pkg[depType]if?(!deps)?returnObject.keys(deps).forEach(dep?=>?{if?(dep?===?'vue'?||(dep.startsWith('@vue')?&&?packages.includes(dep.replace(/^@vue\//,?''))))?{console.log(chalk.yellow(`${pkg.name}?->?${depType}?->?${dep}@${version}`))deps[dep]?=?version}})
}

一圖勝千言。我們在終端執行yarn release --dry。會看到這樣是輸出。

更新 Vue 相關依賴的終端輸出

也就是這句代碼輸出的。

console.log(chalk.yellow(`${pkg.name}?->?${depType}?->?${dep}@${version}`)
)

4.5 打包編譯所有包

//?build?all?packages?with?types
step('\nBuilding?all?packages...')
if?(!skipBuild?&&?!isDryRun)?{await?run('yarn',?['build',?'--release'])//?test?generated?dts?filesstep('\nVerifying?type?declarations...')await?run('yarn',?['test-dts-only'])
}?else?{console.log(`(skipped)`)
}

4.6 生成 changelog

//?generate?changelog
await?run(`yarn`,?['changelog'])

yarn changelog 對應的腳本是conventional-changelog -p angular -i CHANGELOG.md -s

4.7 提交代碼

經過更新版本號后,有文件改動,于是git diff。是否有文件改動,如果有提交。

git add -Agit commit -m 'release: v${targetVersion}'

const?{?stdout?}?=?await?run('git',?['diff'],?{?stdio:?'pipe'?})
if?(stdout)?{step('\nCommitting?changes...')await?runIfNotDry('git',?['add',?'-A'])await?runIfNotDry('git',?['commit',?'-m',?`release:?v${targetVersion}`])
}?else?{console.log('No?changes?to?commit.')
}

4.8 發布包

//?publish?packages
step('\nPublishing?packages...')
for?(const?pkg?of?packages)?{await?publishPackage(pkg,?targetVersion,?runIfNotDry)
}

這段函數比較長,可以不用細看,簡單說就是 yarn publish 發布包。我們 yarn release --dry后,這塊函數在終端輸出的如下:

發布終端輸出命令

值得一提的是,如果是 vue 默認有個 tagnext。當 Vue 3.x 是默認時刪除。

}?else?if?(pkgName?===?'vue')?{//?TODO?remove?when?3.x?becomes?defaultreleaseTag?=?'next'
}

也就是為什么我們現在安裝 vue3 還是 npm i vue@next命令。

async?function?publishPackage(pkgName,?version,?runIfNotDry)?{//?如果在?跳過包里?則跳過if?(skippedPackages.includes(pkgName))?{return}const?pkgRoot?=?getPkgRoot(pkgName)const?pkgPath?=?path.resolve(pkgRoot,?'package.json')const?pkg?=?JSON.parse(fs.readFileSync(pkgPath,?'utf-8'))if?(pkg.private)?{return}//?For?now,?all?3.x?packages?except?"vue"?can?be?published?as//?`latest`,?whereas?"vue"?will?be?published?under?the?"next"?tag.let?releaseTag?=?nullif?(args.tag)?{releaseTag?=?args.tag}?else?if?(version.includes('alpha'))?{releaseTag?=?'alpha'}?else?if?(version.includes('beta'))?{releaseTag?=?'beta'}?else?if?(version.includes('rc'))?{releaseTag?=?'rc'}?else?if?(pkgName?===?'vue')?{//?TODO?remove?when?3.x?becomes?defaultreleaseTag?=?'next'}//?TODO?use?inferred?release?channel?after?official?3.0?release//?const?releaseTag?=?semver.prerelease(version)[0]?||?nullstep(`Publishing?${pkgName}...`)try?{await?runIfNotDry('yarn',['publish','--new-version',version,...(releaseTag???['--tag',?releaseTag]?:?[]),'--access','public'],{cwd:?pkgRoot,stdio:?'pipe'})console.log(chalk.green(`Successfully?published?${pkgName}@${version}`))}?catch?(e)?{if?(e.stderr.match(/previously?published/))?{console.log(chalk.red(`Skipping?already?published:?${pkgName}`))}?else?{throw?e}}
}

4.9 推送到 github

//?push?to?GitHub
step('\nPushing?to?GitHub...')
//?打?tag
await?runIfNotDry('git',?['tag',?`v${targetVersion}`])
//?推送?tag
await?runIfNotDry('git',?['push',?'origin',?`refs/tags/v${targetVersion}`])
//?git?push?所有改動到?遠程??-?github
await?runIfNotDry('git',?['push'])
//?yarn?run?release?--dry//?如果傳了這個參數則輸出?可以用?git?diff?看看更改//?const?isDryRun?=?args.dry
if?(isDryRun)?{console.log(`\nDry?run?finished?-?run?git?diff?to?see?package?changes.`)
}//?如果?跳過的包,則輸出以下這些包沒有發布。不過代碼?`skippedPackages`?里是沒有包。
//?所以這段代碼也不會執行。
//?我們習慣寫 arr.length !==?0?其實?0?就是 false 。可以不寫。
if?(skippedPackages.length)?{console.log(chalk.yellow(`The?following?packages?are?skipped?and?NOT?published:\n-?${skippedPackages.join('\n-?')}`))
}
console.log()

我們 yarn release --dry后,這塊函數在終端輸出的如下:

發布到github

到這里我們就拆解分析完 main 函數了。

整個流程很清晰。

1.?確認要發布的版本
2.?執行測試用例
3.?更新所有包的版本號和內部?vue?相關依賴版本號3.1?updatePackage?更新包的版本號3.2?updateDeps?更新內部?vue?相關依賴的版本號
4.?打包編譯所有包
5.?生成?changelog
6.?提交代碼
7.?發布包
8.?推送到?github

用一張圖總結則是:

vue 發布流程

看完vue-next/scripts/release.js,感興趣還可以看vue-next/scripts文件夾下其他代碼,相對行數不多,但收益較大。

5. 總結

通過本文學習,我們學會了這些。

1.?熟悉?vuejs?發布流程
2.?學會調試?nodejs?代碼
3.?動手優化公司項目發布流程

同時建議自己動手用 VSCode 多調試,在終端多執行幾次,多理解消化。

vuejs發布的文件很多代碼我們可以直接復制粘貼修改,優化我們自己發布的流程。比如寫小程序,相對可能發布頻繁,完全可以使用這套代碼,配合miniprogram-ci[14],再加上一些自定義,加以優化。

當然也可以用開源的 release-it[15]

同時,我們可以:

引入 git flow[16],管理git分支。估計很多人不知道windows git bash已經默認支持 git flow命令。

引入 husky[17] 和 lint-staged[18] 提交commit時用ESLint等校驗代碼提交是否能夠通過檢測。

引入 單元測試 jest[19],測試關鍵的工具函數等。

引入 conventional-changelog[20]

引入 git-cz[21] 交互式git commit

等等規范自己項目的流程。如果一個候選人,通過看vuejs發布的源碼,積極主動優化自己項目。我覺得面試官會認為這個候選人比較加分。

看開源項目源碼的好處在于:一方面可以拓展視野,另外一方面可以為自己所用,收益相對較高。

參考資料

[1]

vue-next: https://github.com/vuejs/vue-next

[2]

更多可點擊 閱讀原文 查看

最近組建了一個江西人的前端交流群,如果你是江西人可以加我微信?ruochuan12?私信 江西?拉你進群。


推薦閱讀

我在阿里招前端,該怎么幫你(可進面試群)
我讀源碼的經歷

初學者也能看懂的 Vue3 源碼中那些實用的基礎工具函數
老姚淺談:怎么學JavaScript?

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》多篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,活躍在知乎@若川,掘金@若川。致力于分享前端開發經驗,愿景:幫助5年內前端人走向前列。

識別方二維碼加我微信、拉你進源碼共讀

今日話題

略。歡迎分享、收藏、點贊、在看我的公眾號文章~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/275529.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/275529.shtml
英文地址,請注明出處:http://en.pswp.cn/news/275529.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

wireshark使用教程 linux,Linux入門教程:ubuntu下安裝wireshark(以及配置非root),這個強大的工具可以捕...

Linux入門教程:ubuntu下安裝wireshark(以及配置非root),這個強大的工具可以捕Wireshark是世界上最流行的網絡分析工具。這個強大的工具可以捕捉網絡中的數據,并為用戶提供關于網絡和上層協議的各種信息。與很多其他網絡工具一樣,Wireshark也使用pcap net…

IronPython和C#執行速度對比

其實我自己對執行速度這個問題本來并沒有什么興趣,因為以前的經驗告訴我:除非是運算密集型的程序,否則腳本語言和編譯型語言使用起來速度沒有多大差別。但是我們公司有個人知道我的想法以后,天天在我耳邊嚷嚷腳本運行速度太慢&…

基于超級賬本Fabric的供應鏈跟蹤解決方案【開源】

2019獨角獸企業重金招聘Python工程師標準>>> 本項目為基于Hyperledger Fabric區塊鏈的供應鏈資產跟蹤解決方案,項目主要包括鏈碼和Web應用兩部分。Fabric鏈碼采用GOLANG開發,負責維護資產的狀態,后臺為采用Node.js開發的Web應用&a…

同理心案例及故事分享_神經形態,視覺可及性和同理心

同理心案例及故事分享“A good UX designer has empathy”.“優秀的UX設計人員具有同理心”。 This is something every UX designer has heard at some point in their career. Empathy helps us get into the mindset of the user and build solutions that solve real probl…

純CSS實現beautiful按鈕

大家好,我是若川。邀你進源碼共讀群學習交流。今天分享一篇好文。可收藏~近期工作中遇到一個需求——實現一些酷炫的按鈕,看到效果圖之后,按鈕確實漂亮,有彈跳、顏色漸變、掃光、霓虹燈,瞬間激起了我的好奇…

linux的內核有多小,Linux 內核有小bug?

今天讀著讀著Linux代碼,竟然無意中發現Linux 0.11內核有個小bug,呵呵,人非圣賢孰能無過。// 在目錄項數據塊中搜索匹配指定文件名的目錄項,首先讓de 指向數據塊,并在不超過目錄中目錄項數// 的條件下,循環執…

菜單窗口_菜單

菜單窗口The Hamburger Menu widget is on every other site nowadays. It has become synonymous with the web and, perhaps even more so, with web development. Have, for instance, a look at Dribbble or Codepen. There you’ll find a fair share of examples. They c…

帝國cms 打開打開轉換表文件失敗!

帝國cms 升級到最新版6.6 后 生成列表頁面和 搜索 時出現 “打開打開轉換表文件失敗!” 跟蹤文件找到 include($file); 這行代碼時出錯非常納悶,這個是php的內部命令啊,跟帝國的編碼應該沒有關系一直沒有再往下細找,只好根據錯誤提…

怎么在PDF上修改文字,PDF修改文字的步驟

怎么在PDF文件上修改文字呢?其實現在的很多的PDF文件上會出現文字錯誤的情況,想要修改PDF文件上面的文字卻不知道怎么修改,想要修改PDF文件還是比較簡單的,使用專業的PDF編輯器就可以進行操作了,下面小編就為大家分享一…

linux raw限制端口訪出,使用Linux raw socket時需要注意的一些問題

本文的copyleft歸gfree.windgmail.com所有,使用GPL發布,可以自由拷貝,轉載。但轉載請保持文檔的完整性,注明原作者及原鏈接,嚴禁用于任何商業用途。作者:gfree.windgmail.com博客:linuxfocus.bl…

讀完 Vue 發布源碼,小姐姐回答了 leader 的提問,并優化了項目發布流程~

大家好,我是若川。這是 源碼共讀 第三期活動,紀年小姐姐的第三次投稿。紀年小姐姐學習完優化了自己的項目發布流程,而且回答了leader對她的提問,來看看她的思考和實踐。第三期是 Vue 3.2 發布了,那尤雨溪是怎么發布 Vu…

小程序背景圖片的坑

本人是前端菜鳥一個,比小白還要白,這完全是自己的經驗總結,并不是要給各位分享什么寶貴經驗哈,各位大佬不喜勿噴,不然會打擊到我的哈哈因為公司要求做幾個小程序的頁面,我不得不拾起丟棄了幾個月的小程序開…

SimpleAdapter類使用方法

SimpleAdapter的構造函數是&#xff1a; public SimpleAdapter (Context context, List<? extends Map<String, ?>> data, int resource, String[] from, int[] to) 官方說明了其各個參數含義&#xff0c;我這里根據自己的理解解釋下&#xff1a; 第一個context&…

小程序 富文本自適應屏幕_自適應文本:跨屏幕尺寸構建可讀文本

小程序 富文本自適應屏幕Many of you may already know about responsive web design. Cited from Wikipedia, responsive web design (RWD) is an approach to web design that makes web pages render well on a variety of devices and windows or screen sizes. The respon…

Vue、React 之間如何實現代碼移植?

大家好&#xff0c;我是若川。面對前端最火的兩個框架&#xff0c;學 React 還是 Vue &#xff1f;這可能是每個前端人都曾糾結過的問題。不過&#xff0c;現在你不用糾結了——因為很多公司都是兩個框架都有大量的應用&#xff0c;取決于不同團隊的技術選型&#xff0c;特別是…

linux mariadb 亂碼,配置mariadb遠程訪問權限,解決數據庫亂碼問題

配置mariadb遠程訪問權限&#xff1a;1)登錄數據庫:# mysql -uroot -p2)配置授權數據庫用戶遠程訪問權限&#xff0c;%表示所有遠程IP&#xff0c;也可以指定IP。WITH GRANT OPTION表示mysql數據庫的grant表中重新加載權限數據&#xff1a;GRANT ALL PRIVILEGES ON *.* TO 用戶…

平面設計師和ui設計師_游戲設計師的平面設計

平面設計師和ui設計師Design is a very ancient practice, but graphic design really found its core principles post World War One. Games are also very ancient but video games are still finding their feet. I think graphic design has a few things to teach people…

從零開發一個命令行腳手架工具 等

大家好&#xff0c;我是若川。今天周末&#xff0c;話不多說&#xff0c;這一次花了幾小時精心為大家挑選了20余篇好文&#xff0c;供大家閱讀學習。本文閱讀技巧&#xff0c;先粗看標題&#xff0c;感興趣可以都關注一波&#xff0c;絕對不虧。前端宇宙小編就職于某大廠&#…

linux的HAL庫函數,STM32 HAL庫 IIC 協議庫函數

/* 第1個參數為I2C操作句柄第2個參數為從機設備地址第3個參數為從機寄存器地址第4個參數為從機寄存器地址長度第5個參數為發送的數據的起始地址第6個參數為傳輸數據的大小第7個參數為操作超時時間 */HAL_I2C_Mem_Write(&hi2c2,salve_add,0,0,PA_BUFF,sizeof(PA_BUFF),0x10)…

pku acm 2140 Herd Sums http://acm.pku.edu.cn/JudgeOnline/problem?id=2140

2140代碼短小精悍&#xff1a;#include<stdio.h> int main() { int cnt0,i; long s; scanf("%ld",&s); for(i1;(i1)*i/2<s;i)if((s-(i-1)*i/2)%i0)cnt; printf("%d\n",cnt); return 0; }轉載于:https://www.cnblogs.com/Chinese-Coder-C…