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

大家好,我是若川。最近組織了源碼共讀活動《1個月,200+人,一起讀了4周源碼》,已經有超50+人提交了筆記,群里已經有超1500人,感興趣的可以點此鏈接掃碼加我微信?ruochuan12

create-vue公開了,可以使用npm init vue@next替代vue-cli快速初始化vue3項目。我粗看了源碼,發現只有300行左右,打算加入到源碼共讀計劃大家一起學習。

沒想到源碼共讀群里的小伙伴 upupming 就很迅速的學習了源碼并且輸出了文章。本文是upupming投稿。

原標題:create-vue 發布并成為官方推薦,未來將替換 vue cli,看看 Vue Contributor Days 說了哪些內容(附 create-vue 源碼解析)


美國時間 2021 年 10 月 7 日早晨,This Dot Media 邀請了 Vue 的核心成員和 Vue Community (例如 Quasar, Ionic 開發者等)的一些主要貢獻者舉辦了一個 Vue Contributor Days 在線會議,長達兩個半小時,會上 vue-cli 的核心貢獻者胖茶也在同一天公開了全新的腳手架工具 create-vue[1],我也是看到 antfu 發推就關注了一下,看完直播回放[2]之后收獲很大,這里做一些總結并且分析一下最新發布的 create-vue 的源碼。

主要關注了尤大的 talk,PPT 鏈接[3]在這里,我轉載到了我的 GitHub 上[4],大家可以下載來看一下最新的進展,另外還有胖茶現場演示了如何使用 create-vue。

1. 主要內容

Vue 3.2 在 2021.08.09 就已經發布了,最重要的就是 <script setup> 不再是實驗階段了,可以穩定使用。之前用過 composition API 的朋友都會覺得比較麻煩,<script setup> 主要是為了作為語法糖簡化其寫法,可以參考文檔[5]和 RFC[6]。Vue 3.2 新增了一些新功能,如 defineCustomElementv-memo 等等。

尤大還提到了新的 Ref Transform 提案,雖然現在 TS 環境下多一個 .value 沒有什么太大的問題,類型提示能夠自動補全做的很好,但是 Ref Transform 提案可以進一步簡化省去 .value 這一步,而且 TS 支持也做好了:

9b25c9e0cd13ecf688f07433a9ac7d35.png
20211009173845

使用 cout = $ref(0) 定義之后,使用 count 的時候會被編譯成 count.value,同時還有一個反向操作 $$,重新把 reactive value 變成 ref。感覺這個簡化確實很有前途,可能會被廣泛使用。

另外 Vue 團隊正在積極準備 3.3 版本,主要集中精力在優化 SSR 相關的功能。可以期待一下。

尤大給出了最新的官方推薦:

501deb370e17a3bbe496524a613b029c.png
20211009174500
  • 推薦使用 create-vue 替換 vue cli,注意如果你的項目如果使用 vue cli 創建的,能夠穩定使用的話,暫時沒有提供轉換成 create-vue 項目的方案,而且也不建議修改大型項目的基礎配置。以后的新項目大家可以使用 create-vue 來創建更加快的應用,因為 create-vue 的模板項目都是基于 vite 來進行構建的了。

  • 推薦使用 VSCode 的 Volar 插件而不是 Vetur 來獲取更好的 TypeScript 支持(script setup 支持地很好, vue-tsc 表現和 volar 一致,因為都是用的一個 language service (@johnsoncodehk 開發的 vscode-vue-languageservice)),卸載 Vetur 安裝 Volar 即可。

  • 狀態管理的話,正在考慮在 vuex next / Pinia (也是新出來的一個狀態管理工具) / vue core 三者中考慮一個新的主推

另外 Vue 3 的官方文檔正在快速更新,新版的文檔可以在 https://github.com/vuejs/docs/tree/next 看到源碼,部署在 https://vue-docs-preview.netlify.app/ 。里面新增了許多 example,可以看 Options API 和 Composition API 兩種格式,Composition API 已經都是用 script setup 來寫的了,另外也有 HTML 和 SFC 兩種不同的版本,感覺用 example 學起來方便很多。同時也提供了 tutorial 和 guide 兩種學習方案,非常體貼。

胖茶介紹了 create-vue 的使用,令人興奮的是,所有的模板現在的構建工具全部都是基于 vite 而不是 vue cli (Webpack) 的了,開發效率大大提升,同時使用 cypress 來作為自動測試的工具。之前 Vue 2 單元測試用的是 Jest,但是 Jest 對 Vue 3 的編譯支持的不是很好,所以選擇了 cypress 同時做單元測試和 E2E 測試。整個 create-vue 包的依賴數量非常少,很多沒有必要的依賴都沒放,而且胖茶自己做了一個預先打包導致下載速度變快了許多。同時創建的模板項目也足夠輕量。

后面 antfu 還介紹了最近他開發的 unplugin[7],支持一個插件寫完,Rollup、Vite、Webpack 4、Webpack 5 都能使用,這個還沒有詳細使用過,下次有機會細看。

2. create-vue 源碼解析

首先看目錄結構:

  • index.js 是整個 CLI 的打包入口,所有邏輯都是從這里開始的

  • utils 包含了用到的一些工具函數

  • template Vue 項目模板,例如默認的 default 模板、帶 router 的模板、帶 ts 支持的模板等等。

  • playground 利用 create-vue 生成的項目的快照結果,在運行 pnpm test 時會用到,測試生成的模板項目代碼的正確性

非常簡潔明了,好在項目處于剛開始的階段,index.js 只有 300 多行,可以很容易了解其中的細節。

2.1 整體流程

  • 使用 prompt 詢問用戶一系列 Yes/No 的問題,看用戶需要哪些 feature,包括 TS, JSX, router, vuex, cypress。同時也會詢問包名和是否覆蓋已經存在的文件夾(如果之前已經創建過內容的話)。

  • 驗證包名是否合法,將不合法包名轉換成合法的。

  • 寫入帶包名和版本號的 package.json

  • 調用 render 函數,首先使用 render('base') 創建一個基礎的模板,接下來按照用戶需要哪些 feature,往已經創建的項目中添加對應的模板,例如 render('config/jsx') 就是對基礎模板添加了 JSX 支持。

  • 如果需要 TS 支持的話,后面有個特殊操作把所有 JS 重命名為 TS。將 jsconfig.json 重命名為 tsconfig.json

  • 默認是所有模板都包含測試的,如果用戶不需要,最后需要刪除一下

  • 判斷當前使用的包管理器是 npm/yarn/pnpm,方便后續輸出 xxx install 提示

  • 生成 README.md

  • 最后輸出提示,提示用戶生成成功并展示綠色(kolorist 這個包用來處理顏色)的提示消息,提示后續操作 cd xxx, xxx install, xxx dev

可以先運行一遍 npm init vue@next 感受一下具體的效果。

2.2 具體分析

可以看到,這里面最重要的還是 render 函數的實現,可以把一個相對目錄下的文件給復制到最終生成的項目里面,同時還需要考慮文件相同的時候需要如何進行合并操作。這里主要看一下 render 函數的實現和一些我們以后可能用到的工具函數。

2.2.1 支持 feature flag

支持類似 npm init vue@next --vuex --ts 這種命令行參數,省去 prompt 提問環節直接開始生成項目。

//?index.jsconst?isFeatureFlagsUsed?=typeof?(argv.default?||?argv.ts?||?argv.jsx?||?argv.router?||?argv.vuex?||?argv.tests)?==='boolean'prompt(
//?...
{name:?'needsTypeScript',//?如果使用了?feature?flag,直接?type?函數返回?null,就不會提問了type:?()?=>?(isFeatureFlagsUsed???null?:?'toggle'),message:?'Add?TypeScript?',initial:?false,active:?'Yes',inactive:?'No'
},
)
//?...

2.2.2 render 函數

//?index.js//?所有模板根目錄位于?template?之下
const?templateRoot?=?path.resolve(__dirname,?'template')
//?傳給一個模板名稱,例如?`base`,對應于?template/base?這個模板
const?render?=?function?render(templateName)?{//?拿到真正的模板路徑?templateDir?之后使用?renderTemplate?將?templateDir?下的內容嘗試生成到?root?中,這里?root?就是之前用戶輸入指定的目標路徑const?templateDir?=?path.resolve(templateRoot,?templateName)renderTemplate(templateDir,?root)
}

template/base 是一個最簡單的所有結果都需要模板,它包括了 .vscodeindex.htmlvite.config.js 等這些基礎性的東西。注意 vite 的理念和 Webpack 不一樣,Webpack 和 esbuild 這些都是以 JS 為入口,但是 vite 是以 index.html 為入口的,使用的時候需要轉換一下思維。這個模板的目錄結構如下:

.
├── _gitignore
├── index.html
├── package.json
├── public
│   └── favicon.ico
└── vite.config.js

注意里面有個 _gitignore 文件,使用 _ 開頭是個慣例,因為以 . 開頭的都是配置文件,會影響一些 CLI 工具和編輯器的行為,所以為了避免影響而使用 _,真正 render 的過程中需要重命名成 . 開頭

我們主要看 renderTemplate 這個函數,位于 util/renderTemplate.js 中。

函數簽名注釋可以看,就是一個復制過程,但是又不完全是直接的復制,需要有一些特殊操作要考慮:

//?utils/renderTemplate.js/***?Renders?a?template?folder/file?to?the?file?system,*?by?recursively?copying?all?files?under?the?`src`?directory,*?with?the?following?exception:*???-?`_filename`?should?be?renamed?to?`.filename`*???-?Fields?in?`package.json`?should?be?recursively?merged*?@param?{string}?src?source?filename?to?copy*?@param?{string}?dest?destination?filename?of?the?copy?operation*/
function?renderTemplate(src,?dest)?{

如果發現傳入的是 src 文件夾的話,遞歸調用 renderTemplate 處理文件夾下的每一個文件或者文件夾:

//?utils/renderTemplate.jsconst?stats?=?fs.statSync(src)if?(stats.isDirectory())?{//?if?it's?a?directory,?render?its?subdirectories?and?files?recusivelyfs.mkdirSync(dest,?{?recursive:?true?})for?(const?file?of?fs.readdirSync(src))?{renderTemplate(path.resolve(src,?file),?path.resolve(dest,?file))}return}

遞歸調用寫好,下面就只需要考慮 src 是文件的情況了。

如果是 package.json 文件,并且目標路徑已經存在,需要先 merge 兩個 JSON 對象,然后將 dependencies, devDependencies, peerDependencies, optionalDependencies 這 4 個字段按照字母序從上到下排列好。

if?(filename?===?'package.json'?&&?fs.existsSync(dest))?{//?merge?instead?of?overwritingconst?existing?=?JSON.parse(fs.readFileSync(dest))const?newPackage?=?JSON.parse(fs.readFileSync(src))const?pkg?=?sortDependencies(deepMerge(existing,?newPackage))fs.writeFileSync(dest,?JSON.stringify(pkg,?null,?2)?+?'\n')return}

如果文件以 _ 開頭,需要重命名成以 . 開頭:

if?(filename.startsWith('_'))?{//?rename?`_file`?to?`.file`dest?=?path.resolve(path.dirname(dest),?filename.replace(/^_/,?'.'))}

2.2.3 deepMergesortDependencies

這里有兩個比較有用的函數,deepMerge 用來 merge 兩個 object,相信這個也是面試的時候常考的一個題目,具體的思路就是如果都是對象的話就繼續遞歸,遞歸到原始類型的時候就可以直接賦值來實現賦值了,而數組的話直接用解構賦值來一個淺拷貝就行了。

const?isObject?=?(val)?=>?val?&&?typeof?val?===?'object'
const?mergeArrayWithDedupe?=?(a,?b)?=>?Array.from(new?Set([...a,?...b]))/***?Recursively?merge?the?content?of?the?new?object?to?the?existing?one*?@param?{Object}?target?the?existing?object*?@param?{Object}?obj?the?new?object*/
function?deepMerge(target,?obj)?{for?(const?key?of?Object.keys(obj))?{const?oldVal?=?target[key]const?newVal?=?obj[key]if?(Array.isArray(oldVal)?&&?Array.isArray(newVal))?{//?key?字段對應的值都是?array,那么使用?destructuring?來?mergetarget[key]?=?mergeArrayWithDedupe(oldVal,?newVal)}?else?if?(isObject(oldVal)?&&?isObject(newVal))?{//?key?字段對應的值都是對象,那么遞歸調用target[key]?=?deepMerge(oldVal,?newVal)}?else?{target[key]?=?newVal}}return?target
}

sortDependencies 是將對象按照 key 進行排序,ES6 標準要求 object 對字符串類型的 key 按照插入序排列,對整數類型的 key 按照升序排列[8],因為依賴項都是 npm 包名,必然以字母開頭,可以按照插入序保證其迭代的時候的順序,從而使得解構賦值能夠拿到正確的順序。

export?default?function?sortDependencies(packageJson)?{const?sorted?=?{}const?depTypes?=?['dependencies',?'devDependencies',?'peerDependencies',?'optionalDependencies']for?(const?depType?of?depTypes)?{if?(packageJson[depType])?{sorted[depType]?=?{}Object.keys(packageJson[depType]).sort().forEach((name)?=>?{sorted[depType][name]?=?packageJson[depType][name]})}}return?{...packageJson,...sorted}
}

2.2.4 清除舊項目 rm -rf

之前經常遇到一個問題是 fs.rmdirSync 這個函數只能刪除空文件夾,非空文件夾會報錯,搜索 Stack Overflow 給的最高票答案是用 rimraf[9],但是這里為了少引入包可以直接實現了遞歸刪除文件的功能。用的是多叉樹深搜中的后序遍歷,因為需要先刪除子文件和子文件夾,才能保證當前文件夾為空。實現如下:

//?utils/directoryTraverse.jsexport?function?postOrderDirectoryTraverse(dir,?dirCallback,?fileCallback)?{for?(const?filename?of?fs.readdirSync(dir))?{const?fullpath?=?path.resolve(dir,?filename)//?如果是文件夾,遞歸if?(fs.lstatSync(fullpath).isDirectory())?{postOrderDirectoryTraverse(fullpath,?dirCallback,?fileCallback)//?子文件和子文件夾都處理好了再來用?dirCallback?處理這個文件夾dirCallback(fullpath)continue}//?如果是文件,直接用?fileCallback?處理fileCallback(fullpath)}
}function?emptyDir(dir)?{postOrderDirectoryTraverse(dir,(dir)?=>?fs.rmdirSync(dir),(file)?=>?fs.unlinkSync(file))
}

這個工具函數也非常有用,又省去了一個 npm install

3. 測試

寫完代碼需要進行測試保證正確性。package.json 中的測試腳本如下所示:

"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",

可以看到,首先是 pretest 運行 npm run build 進行打包,然后運行 npm run snapshot 生成 snapshot,生成快照過程就是各個 feature flag 排列組合一下,調用 create-vue 生成所有的可能的 feature flag 組合的模板結果,結果存放在 playground 文件夾下。排列組合可以使用二進制枚舉實現。代碼如下:

const?featureFlags?=?['typescript',?'jsx',?'router',?'vuex',?'with-tests']//?The?following?code?&?comments?are?generated?by?GitHub?CoPilot.
function?fullCombination(arr)?{const?combinations?=?[]//?for?an?array?of?5?elements,?there?are?2^5?-?1=?31?combinations//?(excluding?the?empty?combination)//?equivalent?to?the?following://?[0,?0,?0,?0,?1]?...?[1,?1,?1,?1,?1]//?We?can?represent?the?combinations?as?a?binary?number//?where?each?digit?represents?a?flag//?and?the?number?is?the?index?of?the?flag//?e.g.//?[0,?0,?0,?0,?1]?=?0b0001//?[1,?1,?1,?1,?1]?=?0b1111//?Note?we?need?to?exclude?the?empty?comination?in?our?casefor?(let?i?=?1;?i?<?1?<<?arr.length;?i++)?{const?combination?=?[]for?(let?j?=?0;?j?<?arr.length;?j++)?{if?(i?&?(1?<<?j))?{combination.push(arr[j])}}combinations.push(combination)}return?combinations
}const?flagCombinations?=?fullCombination(featureFlags)
flagCombinations.push(['default'])for?(const?flags?of?flagCombinations)?{createProjectWithFeatureFlags(flags)
}

之后再運行 test.js,就是對 playground 里面所有的項目依次運行 test:unit:ci(組件單元測試) 和 test:e2e:ci(E2E測試)了:

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'])console.log(`Running?e2e?tests?in?${projectName}`)const?e2eTestResult?=?spawnSync('pnpm',?['test:e2e:ci'])}
}

4. 總結

  • 看尤大的 talk 每次都有比較大的收獲,有很多細小的問題都會解釋的比較清晰,同時對 Vue 的未來規劃能了解一些。

  • create-vue 代碼簡潔,依賴少,啟動快,同時這次全面擁抱 vite 也將是非常好的,拋棄掉 Webpack 之后輕松了許多,開發體驗提升了不少。create-vue 中有不少工具函數可以先記下來,下次需要用到的時候就不愁沒處 copy 啦~

    • 不過 create-vue 現在還沒有給模板添加 eslint 配置,后續可能會加上

參考資料

[1]

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

[2]

直播回放: https://www.youtube.com/watch?v=gpTbH469Qog&ab_channel=ThisDotMedia

[3]

PPT 鏈接: https://docs.google.com/presentation/d/137pQTDQI8O1FHzn2AtjL5tjeTnr8wbON7IonkcNyBVs/edit#slide=id.p

[4]

我的 GitHub 上: https://github.com/upupming/frontend-learning-map/tree/main/slides/State_of_Vue_ThisDot_Meetup_Oct_2021.pdf

[5]

文檔: https://v3.vuejs.org/api/sfc-script-setup.html#basic-syntax

[6]

RFC: https://github.com/vuejs/rfcs/blob/master/active-rfcs/0040-script-setup.md

[7]

unplugin: https://github.com/unjs/unplugin

[8]

ES6 標準要求 object 對字符串類型的 key 按照插入序排列,對整數類型的 key 按照升序排列: https://stackoverflow.com/a/23202095/8242705

[9]

rimraf: https://stackoverflow.com/a/16605300/8242705

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


推薦閱讀

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

老姚淺談:怎么學JavaScript?

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

386942cef0e1bf12c7693b3e71f8fe29.gif

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

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

412073c56707ee5ed303fe4ee7da39a7.png

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

今日話題

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

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

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

相關文章

lynda ux_如何進入UX領域

lynda uxI often get asked “What is the right path I should take to get into UX?” and more often than not, I do not have a direct answer. I usually ask a lot of questions about their background, before assessing their current skills with the things they …

php字符串學習筆記

在這里記錄下今天的所得首先對字符串處理進行分類今天主要記錄有以下字符串的格式化字符串的連接與分割字符串的比較使用字符串函數匹配和替換子字符串使用正則表達式1.字符串的格式化<?php //整理字符串的第一步是清理字符串中的多余的空格 // trim() ltrim() rtrim() // …

This is a Blog Test

Blog Test Hello, everyone! I am going to write blog to record the knowledge about the computer technology involved when I study. Please feel free to comment on any mistakes. Thank you! print("Hello")轉載于:https://blog.51cto.com/12370958/2379111

可以測試體育跑步的軟件,某高校現跑步打卡神器 能檢測出是在走還是跑

[摘要]近日&#xff0c;一批高大上的“陽光跑步神器”在東莞一所高校火了&#xff01;之所以稱之“神器”&#xff0c;是由于這批機器能檢測到你在走路還是在跑步&#xff0c;如果走路數據將中斷。消息一出&#xff0c;學生們有贊成&#xff0c;也有大呼“吃不消”。東莞某高校…

一道很熟悉的前端面試題,你怎么答?

大家好&#xff0c;我是若川。最近這幾年&#xff0c;云計算的普及和 HTML5 技術的快速發展&#xff0c;越來越多的應用轉向了瀏覽器 / 服務器&#xff08;B/S&#xff09;架構&#xff0c;這種改變讓瀏覽器的重要性與日俱增&#xff0c;視頻、音頻、游戲幾大核心場景也都在逐漸…

:尋找指定和的整數對_尋找時間:如何增加設計的時間

:尋找指定和的整數對Good design derives from good thinking. And good thinking is highly correlated to how much time you spend. In every place I’ve been though, every designer seems to be thirsty for more time to design. Why does this happen, to a point whe…

JavaScript命名空間namespace的實現方法

網上有很多了&#xff0c;這里給出一個&#xff0c;其實思路就是A{}; A.b{};其實b是A的一個屬性。只是做了一些封裝&#xff0c;最后的效果是可以直接定義多個namespace&#xff1a; 1: My.namespace("Company", "Company.Feed", "Company.Feed.Mess…

通過MySQL存儲原理來分析排序和鎖

先拋出幾個問題1.為什么不建議使用訂單號作為主鍵?2.為什么要在需要排序的字段上加索引?3.for update 的記錄不存在會導致鎖住全表?4.redolog 和 binlog 有什么區別?5.MySQL 如何回滾一條 sql ?6.char(50) 和 varchar(50) 效果是一樣的么?索引知識回顧對于 MySQL 數據庫而…

1600k 打印頭測試軟件,巧修LQ-1600K打印機打印頭

LQ-1600K 24針中英文打印機&#xff0c;由于其打印速度快、輸出的文字漂亮、軟件兼容性好等優點&#xff0c;在國內得到極為廣泛的應用。但該機的打印頭及打印針驅動電路故障率較高&#xff0c;一旦出現此類故障&#xff0c;打印效果將大打折扣。本人在長期維修工作中&#xff…

linkedin爬蟲_重新設計Linkedin的指導功能-用戶體驗案例研究

linkedin爬蟲為什么選擇導師 Linkedin平臺&#xff1f; (Why mentorship Linkedin platform?) As a recent graduate, I went on Linkedin to seek career advice and mentorship. This idea came so naturally that I was quite surprised by the absence of a complete fea…

POJ 1797 Heavy Transportation 解題報告

分類&#xff1a;圖論&#xff0c;生成樹&#xff0c;最短路&#xff0c;并查集作者&#xff1a;ACShiryu時間&#xff1a;2011-7-28地址&#xff1a;ACShiryus BlogHeavy TransportationTime Limit: 3000MSMemory Limit: 30000KTotal Submissions: 11929Accepted: 3171Descrip…

曾以為只能拿8K,22屆學弟字節校招心路歷程

大家好&#xff0c;我是若川。最近組織了源碼共讀活動《1個月&#xff0c;200人&#xff0c;一起讀了4周源碼》&#xff0c;已經有超50人提交了筆記&#xff0c;群里已經有超1500人&#xff0c;感興趣的可以點此鏈接掃碼加我微信 ruochuan12這篇文章記錄了江西師大學弟進入字節…

王者榮耀cpu測試軟件,你的手機能否玩王者榮耀,主流處理器新版王者榮耀測試...

說道國民級手游&#xff0c;目前來看那絕對是王者榮耀和刺激戰場&#xff0c;之前的話那可是王者榮耀的天下&#xff0c;甚至許多手機廠商在發布新手機的時候會專門公布王者榮耀的幀率&#xff0c;可見王者榮耀帶來的影響有多大。新版王者榮耀隨著王者榮耀的優化和手機系統、硬…

關于MFC遇到的一系列類型轉換問題

1.LPTSTR 轉換成 CString&#xff1a; (1)直接賦值 CString strText; LPTSTR lpszText _T("LPTSTR >> CString"); strText lpszText; ::MessageBox( NULL, strText , _T("標題"), MB_ICONASTERISK|MB_TASKMODAL|MB_OK );(2)CString::Format()格式化…

大蕭條時期什么行業走俏_大流行時期的用戶體驗

大蕭條時期什么行業走俏You’ve read a lot about uncertain times and social distancing. We’re all surrounded by the same words, but what exactly do they mean for the UX people? The nearest future is just the tip of the iceberg. The COVID-19 pandemic is lik…

vsftp虛擬用戶無法上傳文件,解決辦法

vsftp虛擬用戶無法上傳文件&#xff0c;解決辦法 1、打開/etc/vsftpd 目錄中的vsftpd.conf文件&#xff0c;查找&#xff1a;guest_usernamexxx&#xff0c;這里指的是vsftpd虛擬用戶對應的實 際系統用戶。 2、將該xxx用戶的R權限賦予想要上傳的目錄&#xff1a;chown -R xxx.x…

面試官問:來實現一個Promise

大家好&#xff0c;我是若川。最近組織了源碼共讀活動《1個月&#xff0c;200人&#xff0c;一起讀了4周源碼》&#xff0c;已經有超50人提交了筆記&#xff0c;群里已經有超1500人&#xff0c;感興趣的可以點此鏈接掃碼加我微信 ruochuan12 參與&#xff0c;一起學習&#xff…

奇跡暖暖服務器不穩定,閃耀暖暖用土豆當服務器?開服僅半小時就崩潰,無數玩家瘋狂吐槽...

大家好&#xff0c;這里是正驚游戲&#xff0c;我是你們的正驚小弟。繼奇跡暖暖之后&#xff0c;疊紙游戲的3D換裝類游戲《閃耀暖暖》于昨天正式開啟了全平臺公測。就在大家想要上游戲給女兒買好看的衣服時&#xff0c;發現游戲的服務器崩了&#xff0c;誰都登錄不上去&#xf…

D2 日報 2019年4月17日

? 新聞 ?? Is React Translated Yet? ¡S! Sim! はい&#xff01; react 文檔翻譯了多種語言reactjs.org? 開源項目 ?? formal/packages/formal-web at master kevinwolfcr/formal React Hooks 版本的 rc-form&#xff0c;集成了 React 表單組件通用的的非受控值緩…

nda協議_如何將NDA項目添加到您的投資組合

nda協議Being on the job hunt meant I needed to update my portfolio again. I had a new project to add, but it was under an NDA and I couldn’t say too much about it. Since I’ve never had to figure out how to display an NDA project on my portfolio before, I…