Vue 團隊公開快如閃電的全新腳手架工具,未來將替代 Vue-CLI,才300余行代碼,學它!...

1. 前言

大家好,我是若川。歡迎關注我的公眾號若川視野源碼共讀活動ruochuan12

想學源碼,極力推薦之前我寫的《學習源碼整體架構系列》jQueryunderscorelodashvuexsentryaxiosreduxkoavue-devtoolsvuex4koa-composevue-next-releasevue-this等十余篇源碼文章。

美國時間 2021 年 10 月 7 日早晨,Vue 團隊等主要貢獻者舉辦了一個 Vue Contributor Days 在線會議,蔣豪群[1](知乎胖茶[2],Vue.js 官方團隊成員,Vue-CLI 核心開發),在會上公開了`create-vue`[3],一個全新的腳手架工具。

create-vue使用npm init vue@next一行命令,就能快如閃電般初始化好基于viteVue3項目。

本文就是通過調試和大家一起學習這個300余行的源碼。

閱讀本文,你將學到:

1.?學會全新的官方腳手架工具?create-vue?的使用和原理
2.?學會使用?VSCode?直接打開?github?項目
3.?學會使用測試用例調試源碼
4. 學以致用,為公司初始化項目寫腳手架工具。
5.?等等

2. 使用 npm init vue@next 初始化 vue3 項目

create-vue github README[4]上寫著,An easy way to start a Vue project。一種簡單的初始化vue項目的方式。

npm?init?vue@next

估計大多數讀者,第一反應是這樣竟然也可以,這么簡單快捷?

忍不住想動手在控制臺輸出命令,我在終端試過,見下圖。

ff34aafecca8451782b3d485ea71f8c3.png
npm init vue@next

最終cd vue3-projectnpm installnpm run dev打開頁面http://localhost:3000[5]

0cacb1d47e454fe0a2faac6ef3d40468.png
初始化頁面

2.1 npm init && npx

為啥 npm init 也可以直接初始化一個項目,帶著疑問,我們翻看 npm 文檔。

npm init[6]

npm init 用法:

npm?init?[--force|-f|--yes|-y|--scope]
npm?init?<@scope>?(same?as?`npx?<@scope>/create`)
npm?init?[<@scope>/]<name>?(same?as?`npx?[<@scope>/]create-<name>`)

npm init <initializer> 時轉換成npx命令:

  • npm init foo -> npx create-foo

  • npm init @usr/foo -> npx @usr/create-foo

  • npm init @usr -> npx @usr/create

看完文檔,我們也就理解了:

#?運行
npm?init?vue@next
#?相當于
npx?create-vue@next

我們可以在這里create-vue[7],找到一些信息。或者在npm create-vue[8]找到版本等信息。

其中@next是指定版本,通過npm dist-tag ls create-vue命令可以看出,next版本目前對應的是3.0.0-beta.6

npm?dist-tag?ls?create-vue
-?latest:?3.0.0-beta.6
-?next:?3.0.0-beta.6

發布時 npm publish --tag next 這種寫法指定 tag。默認標簽是latest

可能有讀者對 npx 不熟悉,這時找到阮一峰老師博客 npx 介紹[9]、nodejs.cn npx[10]

npx 是一個非常強大的命令,從 npm 的 5.2 版本(發布于 2017 年 7 月)開始可用。

簡單說下容易忽略且常用的場景,npx有點類似小程序提出的隨用隨走。

輕松地運行本地命令

node_modules/.bin/vite?-v
#?vite/2.6.5?linux-x64?node-v14.16.0#?等同于
#?package.json?script:?"vite?-v"
#?npm?run?vitenpx?vite?-v
#?vite/2.6.5?linux-x64?node-v14.16.0

使用不同的 Node.js 版本運行代碼某些場景下可以臨時切換 node 版本,有時比 nvm 包管理方便些。

npx?node@14?-v
#?v14.18.0npx?-p?node@14?node?-v?
#?v14.18.0

無需安裝的命令執行

#?啟動本地靜態服務
npx?http-server
#?無需全局安裝
npx?@vue/cli?create?vue-project
#?@vue/cli 相比 npm init vue@next npx create-vue@next 很慢。#?全局安裝
npm?i?-g?@vue/cli
vue?create?vue-project
d0c2c92db8d148cd440835d9214b1ed4.png
npx vue-cli

npm init vue@nextnpx create-vue@next) 快的原因,主要在于依賴少(能不依賴包就不依賴),源碼行數少,目前index.js只有300余行。

3. 配置環境調試源碼

3.1 克隆 create-vue 項目

本文倉庫地址 create-vue-analysis[11],求個star~

#?可以直接克隆我的倉庫,我的倉庫保留的?create-vue?倉庫的?git?記錄
git?clone?https://github.com/lxchuan12/create-vue-analysis.git
cd?create-vue-analysis/create-vue
npm?i

當然不克隆也可以直接用 VSCode 打開我的倉庫。https://open.vscode.dev/lxchuan12/create-vue-analysis

順帶說下:我是怎么保留 create-vue 倉庫的 git 記錄的。

#?在?github?上新建一個倉庫?`create-vue-analysis`?克隆下來
git?clone?https://github.com/lxchuan12/create-vue-analysis.git
cd?create-vue-analysis
git?subtree?add?--prefix=create-vue?https://github.com/vuejs/create-vue.git?main
#?這樣就把 create-vue 文件夾克隆到自己的 git 倉庫了。且保留的 git 記錄

關于更多 git subtree,可以看Git Subtree 簡明使用手冊[12]

3.2 package.json 分析

//?create-vue/package.json
{"name":?"create-vue","version":?"3.0.0-beta.6","description":?"An?easy?way?to?start?a?Vue?project","type":?"module","bin":?{"create-vue":?"outfile.cjs"},
}

bin指定可執行腳本。也就是我們可以使用 npx create-vue 的原因。

outfile.cjs 是打包輸出的JS文件

{"scripts":?{"build":?"esbuild?--bundle?index.js?--format=cjs?--platform=node?--outfile=outfile.cjs","snapshot":?"node?snapshot.js","pretest":?"run-s?build?snapshot","test":?"node?test.js"},
}

執行 npm run test 時,會先執行鉤子函數 pretestrun-s 是 npm-run-all[13] 提供的命令。run-s build snapshot 命令相當于 npm run build && npm run snapshot

根據腳本提示,我們來看 snapshot.js 文件。

3.3 生成快照 snapshot.js

這個文件主要作用是根據const featureFlags = ['typescript', 'jsx', 'router', 'vuex', 'with-tests'] 組合生成31種加上 default 共計 32種 組合,生成快照在 playground目錄。

因為打包生成的 outfile.cjs 代碼有做一些處理,不方便調試,我們可以修改為index.js便于調試。

//?路徑?create-vue/snapshot.js
const?bin?=?path.resolve(__dirname,?'./outfile.cjs')
//?改成?index.js?便于調試
const?bin?=?path.resolve(__dirname,?'./index.js')

我們可以在forcreateProjectWithFeatureFlags 打上斷點。

createProjectWithFeatureFlags其實類似在終端輸入如下執行這樣的命令

node?./index.js?--xxx?--xxx?--force
function?createProjectWithFeatureFlags(flags)?{const?projectName?=?flags.join('-')console.log(`Creating?project?${projectName}`)const?{?status?}?=?spawnSync('node',[bin,?projectName,?...flags.map((flag)?=>?`--${flag}`),?'--force'],{cwd:?playgroundDir,stdio:?['pipe',?'pipe',?'inherit']})if?(status?!==?0)?{process.exit(status)}
}//?路徑?create-vue/snapshot.js
for?(const?flags?of?flagCombinations)?{createProjectWithFeatureFlags(flags)
}

調試VSCode打開項目,VSCode高版本(1.50+)可以在 create-vue/package.json => scripts => "test": "node test.js"。鼠標懸停在test上會有調試腳本提示,選擇調試腳本。如果對調試不熟悉,可以看我之前的文章koa-compose

調試時,大概率你會遇到:create-vue/index.js 文件中,__dirname 報錯問題。可以按照如下方法解決。在 import 的語句后,添加如下語句,就能愉快的調試了。

//?路徑?create-vue/index.js
//?解決辦法和nodejs?issues
//?https://stackoverflow.com/questions/64383909/dirname-is-not-defined-in-node-14-version
//?https://github.com/nodejs/help/issues/2907import?{?fileURLToPath?}?from?'url';
import?{?dirname?}?from?'path';const?__filename?=?fileURLToPath(import.meta.url);
const?__dirname?=?dirname(__filename);

接著我們調試 index.js 文件,來學習。

4. 調試 index.js 主流程

回顧下上文 npm init vue@next 初始化項目的。

4dfac8627c39d70d8924629dc9152729.png
npm init vue@next

單從初始化項目輸出圖來看。主要是三個步驟。

1.?輸入項目名稱,默認值是?vue-project
2.?詢問一些配置?渲染模板等
3.?完成創建項目,輸出運行提示
async?function?init()?{//?省略放在后文詳細講述
}//?async?函數返回的是Promise?可以用?catch?報錯
init().catch((e)?=>?{console.error(e)
})

4.1 解析命令行參數

//?返回運行當前腳本的工作目錄的路徑。
const?cwd?=?process.cwd()
//?possible?options:
//?--default
//?--typescript?/?--ts
//?--jsx
//?--router?/?--vue-router
//?--vuex
//?--with-tests?/?--tests?/?--cypress
//?--force?(for?force?overwriting)
const?argv?=?minimist(process.argv.slice(2),?{alias:?{typescript:?['ts'],'with-tests':?['tests',?'cypress'],router:?['vue-router']},//?all?arguments?are?treated?as?booleansboolean:?true
})

minimist[14]

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

$?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'?}

比如

npm?init?vue@next?--vuex?--force

4.2 如果設置了 feature flags 跳過 prompts 詢問

這種寫法方便代碼測試等。直接跳過交互式詢問,同時也可以省時間。

//?if?any?of?the?feature?flags?is?set,?we?would?skip?the?feature?prompts//?use?`??`?instead?of?`||`?once?we?drop?Node.js?12?supportconst?isFeatureFlagsUsed?=typeof?(argv.default?||?argv.ts?||?argv.jsx?||?argv.router?||?argv.vuex?||?argv.tests)?==='boolean'//?生成目錄let?targetDir?=?argv._[0]//?默認?vue-projectsconst?defaultProjectName?=?!targetDir???'vue-project'?:?targetDir//?強制重寫文件夾,當同名文件夾存在時const?forceOverwrite?=?argv.force

4.3 交互式詢問一些配置

如上文npm init vue@next 初始化的圖示

  • 輸入項目名稱

  • 還有是否刪除已經存在的同名目錄

  • 詢問使用需要 JSX Router vuex cypress 等。

let?result?=?{}try?{//?Prompts://?-?Project?name://???-?whether?to?overwrite?the?existing?directory?or?not?//???-?enter?a?valid?package?name?for?package.json//?-?Project?language:?JavaScript?/?TypeScript//?-?Add?JSX?Support?//?-?Install?Vue?Router?for?SPA?development?//?-?Install?Vuex?for?state?management??(TODO)//?-?Add?Cypress?for?testing?result?=?await?prompts([{name:?'projectName',type:?targetDir???null?:?'text',message:?'Project?name:',initial:?defaultProjectName,onState:?(state)?=>?(targetDir?=?String(state.value).trim()?||?defaultProjectName)},//?省略若干配置{name:?'needsTests',type:?()?=>?(isFeatureFlagsUsed???null?:?'toggle'),message:?'Add?Cypress?for?testing?',initial:?false,active:?'Yes',inactive:?'No'}],{onCancel:?()?=>?{throw?new?Error(red('?')?+?'?Operation?cancelled')}}])}?catch?(cancelled)?{console.log(cancelled.message)//?退出當前進程。process.exit(1)}

4.4 初始化詢問用戶給到的參數,同時也會給到默認值

//?`initial`?won't?take?effect?if?the?prompt?type?is?null//?so?we?still?have?to?assign?the?default?values?hereconst?{packageName?=?toValidPackageName(defaultProjectName),shouldOverwrite,needsJsx?=?argv.jsx,needsTypeScript?=?argv.typescript,needsRouter?=?argv.router,needsVuex?=?argv.vuex,needsTests?=?argv.tests}?=?resultconst?root?=?path.join(cwd,?targetDir)//?如果需要強制重寫,清空文件夾if?(shouldOverwrite)?{emptyDir(root)//?如果不存在文件夾,則創建}?else?if?(!fs.existsSync(root))?{fs.mkdirSync(root)}//?腳手架項目目錄console.log(`\nScaffolding?project?in?${root}...`)//?生成?package.json?文件const?pkg?=?{?name:?packageName,?version:?'0.0.0'?}fs.writeFileSync(path.resolve(root,?'package.json'),?JSON.stringify(pkg,?null,?2))

4.5 根據模板文件生成初始化項目所需文件

//?todo://?work?around?the?esbuild?issue?that?`import.meta.url`?cannot?be?correctly?transpiled//?when?bundling?for?node?and?the?format?is?cjs//?const?templateRoot?=?new?URL('./template',?import.meta.url).pathnameconst?templateRoot?=?path.resolve(__dirname,?'template')const?render?=?function?render(templateName)?{const?templateDir?=?path.resolve(templateRoot,?templateName)renderTemplate(templateDir,?root)}//?Render?base?templaterender('base')//?添加配置//?Add?configs.if?(needsJsx)?{render('config/jsx')}if?(needsRouter)?{render('config/router')}if?(needsVuex)?{render('config/vuex')}if?(needsTests)?{render('config/cypress')}if?(needsTypeScript)?{render('config/typescript')}

4.6 渲染生成代碼模板

//?Render?code?template.//?prettier-ignoreconst?codeTemplate?=(needsTypeScript???'typescript-'?:?'')?+(needsRouter???'router'?:?'default')render(`code/${codeTemplate}`)//?Render?entry?file?(main.js/ts).if?(needsVuex?&&?needsRouter)?{render('entry/vuex-and-router')}?else?if?(needsVuex)?{render('entry/vuex')}?else?if?(needsRouter)?{render('entry/router')}?else?{render('entry/default')}

4.7 如果配置了需要 ts

重命名所有的 .js 文件改成 .ts。重命名 jsconfig.json 文件為 tsconfig.json 文件。

jsconfig.json[15] 是VSCode的配置文件,可用于配置跳轉等。

index.html 文件里的 main.js 重命名為 main.ts

//?Cleanup.if?(needsTypeScript)?{//?rename?all?`.js`?files?to?`.ts`//?rename?jsconfig.json?to?tsconfig.jsonpreOrderDirectoryTraverse(root,()?=>?{},(filepath)?=>?{if?(filepath.endsWith('.js'))?{fs.renameSync(filepath,?filepath.replace(/\.js$/,?'.ts'))}?else?if?(path.basename(filepath)?===?'jsconfig.json')?{fs.renameSync(filepath,?filepath.replace(/jsconfig\.json$/,?'tsconfig.json'))}})//?Rename?entry?in?`index.html`const?indexHtmlPath?=?path.resolve(root,?'index.html')const?indexHtmlContent?=?fs.readFileSync(indexHtmlPath,?'utf8')fs.writeFileSync(indexHtmlPath,?indexHtmlContent.replace('src/main.js',?'src/main.ts'))}

4.8 配置了不需要測試

因為所有的模板都有測試文件,所以不需要測試時,執行刪除 cypress/__tests__/ 文件夾

if?(!needsTests)?{//?All?templates?assumes?the?need?of?tests.//?If?the?user?doesn't?need?it://?rm?-rf?cypress?**/__tests__/preOrderDirectoryTraverse(root,(dirpath)?=>?{const?dirname?=?path.basename(dirpath)if?(dirname?===?'cypress'?||?dirname?===?'__tests__')?{emptyDir(dirpath)fs.rmdirSync(dirpath)}},()?=>?{})}

4.9 根據使用的 npm / yarn / pnpm 生成README.md 文件,給出運行項目的提示

//?Instructions://?Supported?package?managers:?pnpm?>?yarn?>?npm//?Note:?until?<https://github.com/pnpm/pnpm/issues/3505>?is?resolved,//?it?is?not?possible?to?tell?if?the?command?is?called?by?`pnpm?init`.const?packageManager?=?/pnpm/.test(process.env.npm_execpath)??'pnpm':?/yarn/.test(process.env.npm_execpath)??'yarn':?'npm'//?README?generationfs.writeFileSync(path.resolve(root,?'README.md'),generateReadme({projectName:?result.projectName?||?defaultProjectName,packageManager,needsTypeScript,needsTests}))console.log(`\nDone.?Now?run:\n`)if?(root?!==?cwd)?{console.log(`??${bold(green(`cd?${path.relative(cwd,?root)}`))}`)}console.log(`??${bold(green(getCommand(packageManager,?'install')))}`)console.log(`??${bold(green(getCommand(packageManager,?'dev')))}`)console.log()

5. npm run test => node test.js 測試

//?create-vue/test.js
import?fs?from?'fs'
import?path?from?'path'
import?{?fileURLToPath?}?from?'url'import?{?spawnSync?}?from?'child_process'const?__dirname?=?path.dirname(fileURLToPath(import.meta.url))
const?playgroundDir?=?path.resolve(__dirname,?'./playground/')for?(const?projectName?of?fs.readdirSync(playgroundDir))?{if?(projectName.endsWith('with-tests'))?{console.log(`Running?unit?tests?in?${projectName}`)const?unitTestResult?=?spawnSync('pnpm',?['test:unit:ci'],?{cwd:?path.resolve(playgroundDir,?projectName),stdio:?'inherit',shell:?true})if?(unitTestResult.status?!==?0)?{throw?new?Error(`Unit?tests?failed?in?${projectName}`)}console.log(`Running?e2e?tests?in?${projectName}`)const?e2eTestResult?=?spawnSync('pnpm',?['test:e2e:ci'],?{cwd:?path.resolve(playgroundDir,?projectName),stdio:?'inherit',shell:?true})if?(e2eTestResult.status?!==?0)?{throw?new?Error(`E2E?tests?failed?in?${projectName}`)}}
}

主要對生成快照時生成的在 playground 32個文件夾,進行如下測試。

pnpm?test:unit:cipnpm?test:e2e:ci

6. 總結

我們使用了快如閃電般的npm init vue@next,學習npx命令了。學會了其原理。

npm?init?vue@next?=>?npx?create-vue@next

快如閃電的原因在于依賴的很少。很多都是自己來實現。如:Vue-CLIvue create vue-project 命令是用官方的npm包validate-npm-package-name[16],刪除文件夾一般都是使用 rimraf[17]。而 create-vue 是自己實現emptyDirisValidPackageName

非常建議讀者朋友按照文中方法使用VSCode調試 create-vue 源碼。源碼中還有很多細節文中由于篇幅有限,未全面展開講述。

學完本文,可以為自己或者公司創建類似初始化腳手架。

目前版本是3.0.0-beta.6。我們持續關注學習它。除了create-vue 之外,我們還可以看看create-vite[18]、create-umi[19] 的源碼實現。

最后歡迎加我微信 ruochuan12源碼共讀 活動,大家一起學習源碼,共同進步。

7. 參考資料

發現 create-vue 時打算寫文章加入到源碼共讀比我先寫完文章。

@upupming ?vue-cli 將被 create-vue 替代?初始化基于 vite 的 vue3 項目為何如此簡單?

參考資料

[1]

點擊閱讀原文查看更多

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


推薦閱讀

1個月,200+人,一起讀了4周源碼
我歷時3年才寫了10余篇源碼文章,但收獲了100w+閱讀

老姚淺談:怎么學JavaScript?

我在阿里招前端,該怎么幫你(可進面試群)

48ea46ad379c287f6b6f7d3f2ead7785.gif

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

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動

8b19b9b1a24f52305f09f5a006722c43.png

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

今日話題

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

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

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

相關文章

斑馬無線打印服務器,如何設置斑馬打印機無線WiFi

安裝Zebra Setup Utilities.exe&#xff0c;打開軟件(沒有該軟件的可以向客服索要)界面如果是英文請選擇options(選項)&#xff0c;選擇應用程序語言Simplified Chinese(簡體中文)點擊確定&#xff0c;關閉軟件&#xff0c;重新打開&#xff0c;界面就會顯示中文。點擊相應的打…

Python自然語言處理學習筆記(19):3.3 使用Unicode進行文字處理

3.3 Text Processing with Unicode 使用Unicode進行文字處理 Our programs will often need to deal with different languages, and different character sets. The concept of “plain text” is a fiction&#xff08;虛構&#xff09;. If you live in the English-speakin…

小程序卡片疊層切換卡片_現在,卡片和清單在哪里?

小程序卡片疊層切換卡片重點 (Top highlight)介紹 (Intro) I was recently tasked to redesign the results of the following filters:我最近受命重新設計以下過濾器的結果&#xff1a; Filtered results for users (creatives) 用戶的篩選結果(創意) 2. Filtered results fo…

記一次Sentry部署過程

前言 Sentry 是一個開源的實時錯誤報告工具&#xff0c;支持前后端、其他后端語言以及主流框架等。既然是開源&#xff0c;那么我們可以在自己的服務器上搭建&#xff0c;本文記錄搭建的過程以及搭建過程中遇到的一些問題&#xff0c;也可以跟著這個教程來搭建一遍 部署環境 Ub…

效率神器!UI 稿智能轉換成前端代碼

做前端&#xff0c;不搬磚大家好&#xff0c;我是若川。從事前端五年之久&#xff0c;也算見證了前端數次變革&#xff0c;從到DW&#xff08;Dreamweaver&#xff09;到H5C3、從JQuery到MVC框架&#xff0c;無數前端大佬在為打造前端完整生態做出努力&#xff0c;由于他們的努…

$.when.apply_When2Meet vs.LettuceMeet:UI和美學方面的案例研究

$.when.apply并非所有計劃應用程序都是一樣創建的。 (Not all scheduling apps are created equal.) As any college student will tell you, we use When2Meet almost religiously. Between classes, extracurriculars, work, and simply living, When2Meet is the scheduling…

BZOJ4825: [Hnoi2017]單旋(Splay)

題面 傳送門 題解 調了好幾個小時……指針太難寫了…… 因為只單旋最值&#xff0c;我們以單旋\(\min\)為例&#xff0c;那么\(\min\)是沒有左子樹的&#xff0c;而它旋到根之后&#xff0c;它的深度變為\(1\)&#xff0c;它的右子樹里所有節點深度不變&#xff0c;其它所有節點…

前端不容你褻瀆

大家好&#xff0c;我是若川&#xff0c;點此加我微信進源碼群&#xff0c;一起學習源碼。同時可以進群免費看Vue專場直播&#xff0c;有尤雨溪分享「Vue3 生態現狀以及展望」背景最近我在公眾號的后臺收到一條留言&#xff1a;言語里充滿了對前端的不屑和鄙夷&#xff0c;但仔…

用jquery阻止事件起泡

jquery使用過程中阻止事件起泡實例 1、通過返回false來取消默認的行為并阻止事件起泡。jQuery 代碼:$("form").bind("submit", function() { return false; })2、通過使用 preventDefault() 方法只取消默認的行為。jQuery 代碼:$("form").bind(…

利益相關者軟件工程_如何向利益相關者解釋用戶體驗的重要性

利益相關者軟件工程With the ever increasing popularity of user experience (UX) design there is a growing need for good designers. However, there’s a problem for designers here as well. How can you show the importance of UX to your stakeholders and convince…

云棲大會上,阿里巴巴重磅發布前端知識圖譜!

大家好&#xff0c;我是若川&#xff0c;點此加我微信進源碼群&#xff0c;一起學習源碼。同時可以進群免費看Vue專場直播&#xff0c;有尤雨溪分享「Vue3 生態現狀以及展望」阿里巴巴前端知識圖譜&#xff0c;由大阿里眾多前端技術專家團歷經1年時間精心整理&#xff0c;從 初…

Linux下“/”和“~”的區別

在linux中&#xff0c;”/“代表根目錄&#xff0c;”~“是代表目錄。Linux存儲是以掛載的方式&#xff0c;相當于是樹狀的&#xff0c;源頭就是”/“&#xff0c;也就是根目錄。 而每個用戶都有”家“目錄&#xff0c;也就是用戶的個人目錄&#xff0c;比如root用戶的”家“目…

在當今移動互聯網時代_誰在提供當今最好的電子郵件體驗?

在當今移動互聯網時代Hey, a new email service from the makers of Basecamp was recently launched. The Verge calls it a “genuinely original take on messaging”, and it indeed features some refreshing ideas for the sometimes painful exercise we call inbox man…

插件式開發小記

在做插件開發時&#xff0c;小記一下&#xff0c;用來備忘&#xff1a; 1.DEV8.2的XtraTabControl控件如何獲得當前打開的子窗體&#xff1a;XtraForm frm (XtraForm)xtraTabControl1.SelectedTabPage.Controls[0];2.插件開發的底層標準最好是抽象類&#xff0c;這樣擴展性好。…

linux運維工程師學習路線

一、學習路線&#xff1a; 1.青銅&#xff1a; 1、Linux基礎知識、基本命令&#xff08;起源、組成、常用命令如cp、ls、file、mkdir等常見操作命令&#xff09; 2、Linux用戶及權限基礎 3、Linux系統進程管理進階 4、linux高效文本、文件處理命令&#xff08;vim、grep、sed、…

React 全新文檔上線!

大家好&#xff0c;我是若川&#xff0c;點此加我微信進源碼群&#xff0c;一起學習源碼。同時可以進群免費看明天的Vue專場直播&#xff0c;有尤雨溪分享「Vue3 生態現狀以及展望」&#xff0c;還可以領取50場錄播視頻和PPT。React 官方文檔改版耗時 1 年&#xff0c;今天已完…

POJ2392

題意:奶牛們要用K個不同類型的石頭建太空電梯.每一種石頭的高度為Hi&#xff0c;數量為Ci,且不能放在高于Ai的地方,求最高能建多高的太空電梯. 分析:多重背包,數組標記.顯然將ai小的放在下面會更優.所以先排序. code: const maxh41000; var cnt:array[0..maxh] of longint;h,…

網絡低俗詞_從“低俗小說”中汲取7堂課,以創建有影響力的作品集

網絡低俗詞重點 (Top highlight)Design portfolios and blockbuster movies had become more and more generic. On the design side, I blame all the portfolio reviews and articles shared by “experienced” designers that repeat the same pieces of advice regardless…

Vue多個組件映射到同一個組件,頁面不刷新?

問題 在做項目的過程中,有這么一個場景&#xff1a;多個組件通過配置路由,都跳轉到同一個組件,他們之間的區別就是,傳入的參數不同.請看router對象&#xff1a; userCenterLike: {name: user-center,params: {index: 0}},userCenterHistory: {name: user-center,params: {index…

尤雨溪寫的100多行的“玩具 vite”,十分有助于理解 vite 原理

1. 前言大家好&#xff0c;我是若川。最近組織了源碼共讀活動&#xff0c;感興趣的可以加我微信 ruochuan12想學源碼&#xff0c;極力推薦之前我寫的《學習源碼整體架構系列》jQuery、underscore、lodash、vuex、sentry、axios、redux、koa、vue-devtools、vuex4、koa-compose、…