bensonliao / blog Goto Github PK
View Code? Open in Web Editor NEWThis project forked from flameddd/blog
my work blog
This project forked from flameddd/blog
my work blog
Recently I've got my new laptop that is Windows platform,
and my previous notebook was MacBook Pro,
so here's some note for the working environment setup.
AFAIK, posh-git is one of the best tools to integrate with Powershell,
so there's some related setup based on this environment.
When we run ssh-agent via the command eval "$(ssh-agent -s)"
in Powershell,
which is not able to run because it's the wrong console,
Powershell has its own way to do so with posh-git,
before v1.0 we're all set,
but after v1.0,
posh-git has removed all ssh related commands and moved into a new module called posh-sshell,
so here's the way to run ssh-agent,
notepad $PROFILE
)
Import-Module posh-git
Import-Module posh-sshell
Start-SshAgent
When we declare the media queries,
beware of the order between them,
they're important when it comes to the same CSS specificity that the only difference is the order of declaration,
see the live demo
ref.
How to set rwd in css
What is the order of precedence for CSS?
如果我們有多個暫存變動
想要指定套用特定的變動
可以在pop
或apply
指定stash index:
git stash apply stash@{n}
git 2.11之後 git stash apply n
假設現在有這些變動
stash@{0}: On OOO406EE-custom-health-cs-monthly-report: monthly report stress test
stash@{1}: On OOO406EE-custom-health-cs-monthly-report: improve scrm chat input behavior
stash@{2}: WIP on use-feature-flag-to-customization: ab5a2080b feat: rollback action type select getter, use general name to render customized logo
stash@{3}: WIP on OOO3F2D1-contract-expiry-notice: a835da154 Fix:Remove debug code.
stash@{4}: WIP on OOO3F2D1-contract-expiry-notice: f8cbeeb64 Feat:ContractExpiryNoticeSerializer add organization id.
stash@{5}: WIP on locate-liff-entry-point: 7c2b0e4b1 Merge branch 'feature/scrm/locate-liff-entry-point' of github.com:beBit-tech/Omnisegment into feature/scrm/locate-liff-entry-point
stash@{6}: WIP on locate-liff-entry-point: 638de8271 refactor
我們可以下 git stash apply stash@{4}
或 git stash apply 4
來套用上面數過來第五個暫存變動
值得一提的是 pop
在這邊就跟熟悉的 Array.pop
不一樣
pop
也可以指定stash index
git同樣會套用跟移除然後更新index
比如上面的列表執行 git stash pop 1
之後:
stash@{0}: On OOO406EE-custom-health-cs-monthly-report: monthly report stress test
stash@{1}: WIP on use-feature-flag-to-customization: ab5a2080b feat: rollback action type select getter, use general name to render customized logo
stash@{2}: WIP on OOO3F2D1-contract-expiry-notice: a835da154 Fix:Remove debug code.
stash@{3}: WIP on OOO3F2D1-contract-expiry-notice: f8cbeeb64 Feat:ContractExpiryNoticeSerializer add organization id.
stash@{4}: WIP on locate-liff-entry-point: 7c2b0e4b1 Merge branch 'feature/scrm/locate-liff-entry-point' of github.com:beBit-tech/Omnisegment into feature/scrm/locate-liff-entry-point
stash@{5}: WIP on locate-liff-entry-point: 638de8271 refactor
ref: https://stackoverflow.com/questions/1910082/git-stash-apply-version
大多數的react開發者應該都知道CRA這個官方提供的開發工具吧~
優點是方便快速幾乎不用什麼設定就能開發好一個網頁應用程式,
但是相對的缺點也恰好就是:
不用什麼設定
因為CRA都幫你設定好了,但你也不能動lol
這代表假設要使用某些webpack-plugin / loader之類,
比如說今天要說的主題之一:worker-loader
或者是要自訂如何做code-splitting等等方式來優化都是沒辦法的。
當然如果你是webpack調教高手,我想這篇可以跳過了
這篇是給還在用CRA的新中老手們參考的,
OK~那麼本文開始!
談到前端優化,最近這東東似乎滿多人在討論的,
目前已知的優化方式包括lazy import等等這邊就不贅述了,
今天要說的是Web Workers。
我們都知道網頁執行緒是單線程,
一旦程式碼複雜肥大或存在所謂的Heavy Operation / Computation,
就會造成網頁載入時間變長,
連帶影響到TTFI(Time To First Interactive),
使用者就會感覺到網頁載入變慢了。
Web Worker就是解決單線程塞車的利器之一,
為JavaScript 創造多線程的環境,
讓主線程可以建立Worker線程,
將一些任務分配给Worker線程執行。
在主線程執行的同时,Worker線程在背景執行,兩者互不干擾,
等到Worker線程完成執行,再把结果回傳给主線程。
但就官方角度這不在CRA處理範圍,
所以文章開頭提到的worker-loader自然也無法使用。
雖然先前也有一些人在討論加入worker-loader的支援或甚至也有人提出PR,
不過目前CRA尚未將worker-loader納入,
OK,那我們只能eject了嗎?
不,我們還有選擇!
答案是可以的!
使用工具:react-app-rewired
Repo的描述就明白的告訴我們
Override create-react-app webpack configs without ejecting
那麼接下來簡單說明一下如何使用,以搭配worker-loader為例
安裝react-app-rewired, worker-loader
npm install react-app-rewired worker-loader --save-dev
or
yarn add -D react-app-rewired worker-loader
在repo根目錄建立config-overrides.js
並在config-overrides.js中貼上以下範例程式碼
/* eslint-disable no-param-reassign */
module.exports = function override(config) {
// Add rules to use worker-loader on specific files
config.module.rules.push({
test: /worker\.js$/,
use: { loader: 'worker-loader' }
})
// Add the line below to avoid: Uncaught ReferenceError: window is not defined
config.output.globalObject = 'this'
return config
}
worker.js
並在worker.js中貼上以下範例程式碼/* eslint-disable no-restricted-globals */
self.addEventListener('message', event => {
console.log('event.data', event.data) // You should see 'event.data: init'
postMessage('Success')
})
index.js
中貼上以下範例程式碼......
import Worker from './worker' // Path depends on where you put 'worker.js'
......
const worker = new Worker()
worker.postMessage('init')
console.log('Message posted to worker')
worker.onmessage = event => {
console.log('Message received from worker')
console.log('event.data:', event.data) // You should see 'event.data: Success'
}
......
package.json
中script區塊start
,build
,test
的執行指令開頭react-script
替換成react-app-rewired
eject
不需更動"scripts": {
......
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom",
"eject": "react-scripts eject"
......
......
},
完成!好好享受Web Worker帶來的優化體驗吧~
應用專案:結合redux在worker中回傳redux action,主執行緒收到後呼叫store.dispatch觸發store更新,本專案只應用在網頁載入後首次取得資料,不過目前Web Workers似乎會跟底層的Fiber Architecture有複雜的交互運作問題,加上Web Workers的流程控制脫離了React本身,需要做額外處理或是利用一些套件(還沒測試),雖然對優化有很大幫助,在釐清跟底層會有哪些影響之前可能還是先不要全面改用Web Workers比較保險:)
參考Dan大神的Twitter
worker.js
/* eslint-disable no-restricted-globals */
import { createPostData } from './utils/dataMock'
import { getNormalizedData, PostSchema } from './utils/dataSchema'
import { addData } from './actions'
const preloadedState = createPostData()
const normalizedData = getNormalizedData(preloadedState, PostSchema)
self.addEventListener('message', event => {
console.log('event.data', event.data)
postMessage(addData(normalizedData)) // Return redux action to main thread
})
index.js
......
import Worker from './worker' // Path depends on where you put 'worker.js'
......
const worker = new Worker()
worker.postMessage('init')
console.log('Message posted to worker')
worker.onmessage = event => {
console.log('Message received from worker')
store.dispatch(event.data) // Dispatch redux action from worker message
}
const App = React.lazy(() => import('./components/App'))
ReactDOM.render(
<Provider store={store}>
<Suspense fallback={<div>Loading...</div>}>
<App postData={post} />
</Suspense>
</Provider>,
document.getElementById('root')
)
實測優化結果:audits的performance分數來到了95!(沒有使用之前最多7x,沒用lazy import更只有5x)
具體步驟參考這篇跟留言遇到的錯誤情況作修正。
以上,如有謬誤歡迎補充或指正:)
When working with remote git repo and there were several merge requests have been made,
our local branch will still exist even if remote branch was deleted.
What if we want to easily delete all that branch from local?
git config remote.origin.prune true
.
https://stackoverflow.com/questions/18308535/automatic-prune-with-git-fetch-or-pull
With the following command combination:
git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d
Additional you can also add option -p
to args
to prompt before execution:
git branch --merged master | grep -v '^[ *]*master$' | xargs -p git branch -d
This command will output the received standard input or pipeline first and prompt you like:
git branch -d add-api-comments refactor-dev-code-structure update-dependencies?...
Then you can type n
to abort execution or y
to execute it, if you type y
and output will like:
git branch -d add-api-comments refactor-dev-code-structure update-dependencies?...y
Deleted branch add-api-comments (was 6d9145a).
Deleted branch refactor-dev-code-structure (was 205c2d0).
Deleted branch update-dependencies (was 2c0cc5d).
Prompt user per branch basis
git branch --merged master | grep -v '^[ *]*master$' | tr -d ' ' | xargs -p -n 1 git branch -d
and the output will like:
git branch -d BensonLiao/issue4473?...y
Deleted branch BensonLiao/issue4473 (was 3a843f3c66).
git branch -d BensonLiao/issue4673?...y
Deleted branch BensonLiao/issue4673 (was 974e967471).
And let's figure it out what those command do...
git branch --merged master
add-api-comments
* master
refactor-dev-code-structure
update-dependencies
grep -v '^[ *]*master$'
xargs git branch -d
xargs
will receive from standard input or pipeline as arguments and run the command after xargs
, so this command will run delete branch from merged branches except masterref: StackOverflow
ref: xargs examples
Git ref其實是類似指標的結構,
在切換分支時其實git背後做了這樣的事: ln -sf refs/heads/newbranch .git/HEAD
,
所以假設在不區分大小寫的檔案系統上如OSX,
創了Bugfix
的分支,
相當於建立了一個不區分大小寫的指標,
也就是bugfix
或Bugfix
都會指到同一個ref folder,
未來假設要創bugfix
也會提示你已經存在,
但是在有區分大小寫的檔案系統中如Windows會有找不到指標的問題,
我們可以直接改.git/refs/heads
的資料夾名稱來解決這樣的情況.
revert
, rebase
and reset
revert
:If u want to revert by the last n commits, try git revert <rev>~<n>
If u want to revert the specific commit, try git revert <sha1-id>
.
can be full 40 digits or a leading substring that is unique within the repository.
Note. like any type of parameter above, this will revert to the 's parent commit object, so actually the commands will revert to the earlier one commit of the commit object
There are more parameter can be used, see https://git-scm.com/docs/gitrevisions
rebase
:rebase
are not rewrite history but append with it.reset
:git revert
is your friend.git rebase
or git reset
.git branch test_branch
git checkout -b test_branch
to skip step 2.git checkout test_branch
git rebase <sha1-id>
or git reset --hard <sha1-id>
There are also have more parameter can be used, see https://git-scm.com/docs/gitrevisions
to be continue...
If you're using the ESLint extension, you can customize the severity of ESLint rules using the setting eslint.rules.customizations.
For example, if you add the following snippet to your .vscode/settings.json, all ESLint errors will be shown as warnings in VSCode.
"eslint.rules.customizations": [
{ "rule": "*", "severity": "warn" }
]
The basic step can be found at here.
But how to actually test our package before publish?
Here's a few step to do using npm link
:
$ cd <you_package_repo>
$ npm link
npm link package-name
will create a symbolic link from globally-installed package-name to node_modules/ of the current folder. e.g. usr/local/lib/node_module/@scope-name/package-name
$ cd <other_repo>
$ npm i usr/local/lib/node_module/@scope-name/package-name
When package test success, you can publish by npm publish --access public
under package repo.
And after publish success, don't forget to unlink npm local registry by npm unlink
under package repo or npm unlink @scope-name/package-name
Before npm < 5.0.0, you will run npm install --save
( shorthand ver. npm i -S
) as dependencies or npm install --save-dev
( shorthand ver. npm i -D
) as devDependencies.
As of npm >= 5.0.0, it's default so you just have to run npm install
( shorthand ver. npm i
)
we should run npm uninstall <package_name>
( shorthand ver. npm un <package_name>
) for specific package or try npm uninstall *
(note. it will fail on some environment so use it carefully) or try npm uninstall `ls -x node_modules`
.
we should run npm update
for all the installed package or npm update <package_name>
for specific package.
npm will look at your package.json and follow the semvar's version prefix notation for certain update behavior, prefix caret ^
for the latest minor version eg. ^1.1.2
:= 1.x.x
and prefix tilde ~
for the latest patch version eg. ~1.1.0
:= 1.1.x
.
And prefix caret are different when version are below 1.0.0, it will act like prefix tilde and looking for the latest patch version eg. ^0.1
:= 0.1.x
.
This is a helpful feature when doing refactor,
but recently we've encounter a problem when in comes to the Typescript files,
it still works on the other Javascript files in the same project,
but not works on Typescript files.
The solution I found is to select specific version of Typescript by command pallet.
reset <commit-sha-id> --hard
but it only do delete, what if we want to alter it?git filter-branch
git filter-branch -f --env-filter "if [[ \$GIT_AUTHOR_EMAIL = '[email protected]' ]]; then [email protected]; fi" HEAD
git filter-branch -f --env-filter "if [[ \$GIT_AUTHOR_EMAIL = '[email protected]' ]]; then GIT_AUTHOR_NAME=myname; [email protected]; fi" HEAD
git filter-branch -f --env-filter "if [[ \$GIT_AUTHOR_EMAIL = '[email protected]' ]]; then [email protected]; fi" HEAD
git status
, you'll see the following message:On branch feature/refactor
Your branch and 'origin/feature/refactor' have diverged,
and have 19 and 19 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
nothing to commit, working tree clean
git push -f
to force update or you'll see Git rejected: ! [rejected] 1.5.0 -> 1.5.0 (non-fast-forward)
error: failed to push some refs to '[email protected]:/xxx/.git'
To prevent you from losing history, non-fast-forward updates were rejected
Merge the remote changes (e.g. 'git pull') before pushing again. See the
'Note about fast-forwards' section of 'git push --help' for details.
Feature:
// A javascript object
const myObject = { x: 1, y: 2 };
// Destructuring
const { x, y } = myObject;
// x is 1, y is 2
function myFunction(text = "", line = 0, truncate = 100) {
// With default values, we can avoid a bunch of:
text = text || "";
line = line || 0;
truncate = truncate || 100;
}
function myFunction(config) {
}
// Usage
myFunction({
text: "Some value",
line: 0,
truncate: 100
})
function myFunction({ text, line, truncate }) {
}
function myFunction({
text = "",
line = 0,
truncate = 100
} = {}) {
// Even if the passed in object is missing a given key, the default is used!
}
= {}
is important, with no default the following example would throw an error:TypeError: Cannot destructure property `key` of 'undefined' or 'null'
const Input = props => {
return (
<div className={props.wrapClass}>
<label
htmlFor={props.id}
className={props.labelClass}
>
{props.label}
</label>
<input
type={props.type}
id={props.id}
placeholder={props.placeholder}
value={props.value}
onChange={(e) => props.onchange(e.target.value)}
className={props.inputClass} />
</div>
)
}
class App extends Component {
state = {
name: ""
}
changeName = newName => {
this.setState({ name: newName })
}
render() {
return (
<div>
<Input
type="text"
id="name"
label="Name"
placeholder="Enter your name"
value={this.state.name}
onChange={changeName}
labelClass="form-label"
inputClass="form-input"
wrapClass="form-input-wrap"
/>
<p>Hello {this.state.name}</p>
</div>
);
}
}
function Input ({id, label, onChange, labelClass, inputClass, wrapClass, ...props}) {
return (
<div className={wrapClass}>
<label
htmlFor={id}
className={labelClass}
>
{label}
</label>
<input
id={id}
{...props}
onChange={(e) => onChange(e.target.value)}
className={inputClass} />
</div>
)
}
先放參考資料
https://www.bnext.com.tw/article/66831/odysee-in-taiwan
https://blog.simpleinfo.cc/shasha77/what-is-lbry
簡評
npm i <package-name>
not automatically install all the dependencies that package require.echo
, $()
and sed
,echo will re-print to standard output to the terminal, $() will turn the command inside the braces to a string variable, and sed will do regex.
So let's try: npm i $(echo $(npm info react-scripts@latest dependencies) | sed -E "s/,|\'|{ | }//g; s/: /@/g")
A detailed about the command:
npm info react-scripts@latest dependencies
echo $(npm info react-scripts@latest dependencies)
sed -E "s/,|\'|{ | }//g; s/: /@/g"
npm info
will format the result, so we will use regex to clean format$(echo $(npm info react-scripts@latest dependencies) | sed -E "s/,|\'|{ | }//g; s/: /@/g")
npm i
There's many of articles on the internet to tell you how to do it like this,
but not a fully coverage of pre-process and afterwards like updating.
So let's talk about the whole walkthrough:
username.github.io
master
branchgh-pages
branchmaster
branchnpm run build
then npm run deploy
(note. if your script in package.json are properly set at step.3) and you're good to go, enjoy :)Test if command work for update a package and also package.json
:
yarn upgrade package --latest
yarn upgrade package@latest
yarn version: 17.1.3
ref
我們都知道eslint的好處
但是在這變化快速的時代
eslint所用的rule也常常更新
但有時候原作者是將舊rule標為deprecated而不是直接刪除
我們在安裝哪些plugin的時候就會一併將新舊rule一起裝進來了
這時候可能會在編輯器發現這樣的錯誤提示
我們好奇這個rule的詳細說明點進官方文件發現原來其中一個已經deprecated!!
靠已經不用還放進package裡面!(心裡默默罵幹)
好啦罵歸罵事情還是要解決
於是我們按照官方文件給的選項調整還能怎麼做呢?
就是直接在設定檔取消那個rule
以上面圖為例
label-has-for是已經deprecated的rule
所以我們在.eslintrc / eslintrc.json中把加入一行把這個rule的值設定成0
如下方代碼中第二行rule設定
"rules": {
"react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }],
"jsx-a11y/label-has-for": 0,
"prettier/prettier": ["error"]
}
如此便可以甩開已經不用的rule
繼續開心coding了:)
Prerequisites:
When you change to a new machine and you've cloned some repo to update/publish packages again,
you may see the following error when run npm publish
:
npm ERR! code E404
npm ERR! 404 Not Found - PUT https://registry.npmjs.org/@benson.liao%2fcapybara-router - Not found
npm ERR! 404
npm ERR! 404 '@benson.liao/[email protected]' is not in the npm registry.
npm ERR! 404 You should bug the author to publish it (or use the name yourself!)
npm ERR! 404
npm ERR! 404 Note that you can also install from a
npm ERR! 404 tarball, folder, http url, or git url.
This because you have no log in to npm registry,
you can run npm whoami
to check the login status,
if fail you may see the following error:
npm ERR! code ENEEDAUTH
npm ERR! need auth This command requires you to be logged in.
npm ERR! need auth You need to authorize this machine using `npm adduser`
and if success you will see your user name.
So we need to login to be able to perform authenticate action like npm publish
,
by running npm adduser
or npm login
(you can check doc for further information),
and you'll be prompt to enter username, password and/or email like:
Username: benson.liao
Password:
Email: (this IS public) [email protected]
Logged in as benson.liao on https://registry.npmjs.org/.
And finally if the published npm packages have tags and you just clone/pull it with default option,
the tag list on your local machine won't be update,
you'll need to pull/fetch with -t
to sync tag list from remote repo before publish new version.
(Note. remember to reset your local git to commit hash before your failed publish commit if you try to publish without login like this article mentioned from the start)
git reset/revert/rebase
or just change code onward.git stash
to keep a stash of your working changes, a restore from it.git stash list
will tell you the stashes you createdgit stash
git stash -u
git stash apply
git add <files_or_dirs>
, those files or dirs will staged)git stash apply --index
As this SO_article mentioned, inappropriate use of * would slow down the performance.
But need further investigate and/or experiment to clarify the issue.
To be continue...
// A javascript object
const myObject = { x: 1, y: 2, z: 3 }
// ES5 and before with all the dot notations
console.log(myObject.x) // x is 1
console.log(myObject.y) // y is 2
console.log(myObject.z) // y is 3
// Destructuring
const { x, y, z } = myObject
// Cleaner code!
console.log(x) // x is 1
console.log(y) // y is 2
console.log(z) // y is 3
function myFunction(text = "", line = 0, truncate = 100) {
// With default values, we can avoid a bunch of:
text = text || "";
line = line || 0;
truncate = truncate || 100;
}
function myFunction(config) {
}
// Usage
myFunction({
text: "Some value",
line: 0,
truncate: 100
})
function myFunction({ text, line, truncate }) {
}
function myFunction({
text = "",
line = 0,
truncate = 100
} = {}) {
// Even if the passed in object is missing a given key, the default is used!
}
= {}
is important, with no default the following example would throw an error:TypeError: Cannot destructure property `key` of 'undefined' or 'null'
const Input = props => {
return (
<div className={props.wrapClass}>
<label
htmlFor={props.id}
className={props.labelClass}
>
{props.label}
</label>
<input
type={props.type}
id={props.id}
placeholder={props.placeholder}
value={props.value}
onChange={(e) => props.onchange(e.target.value)}
className={props.inputClass} />
</div>
)
}
class App extends Component {
state = {
name: ""
}
changeName = newName => {
this.setState({ name: newName })
}
render() {
return (
<div>
<Input
type="text"
id="name"
label="Name"
placeholder="Enter your name"
value={this.state.name}
onChange={changeName}
labelClass="form-label"
inputClass="form-input"
wrapClass="form-input-wrap"
/>
<p>Hello {this.state.name}</p>
</div>
);
}
}
const Input = ({id, label, onChange, labelClass, inputClass, wrapClass, ...props}) => {
const handleChange = event => {
onChange(event.target.value)
}
return (
<div className={wrapClass}>
<label
htmlFor={id}
className={labelClass}
>
{label}
</label>
<input
id={id}
{...props}
onChange={handleChange}
className={inputClass} />
</div>
)
}
這概念老實說一直困擾著我,
很難真正理解跟內化,
尤其是前幾年ES6開始出現promise這樣的機制,
又把非同步任務調派提高到另一層級的理解複雜度XD
原本以為自己終於能摸熟運作機制,
像是下面的例子:
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
console.log('script start');
setTimeout(function () {
console.log('setTimeout');
}, 0);
async1();
new Promise(function (resolve) {
console.log('promise1');
resolve();
}).then(function () {
console.log('promise2');
});
以最新的Chrome 97.0.4692.71為環境下會印出下面的結果(FF 96.0跟Edge 97.0.1072.62是一樣的):
script start
async1 start
async2
promise1
async1 end
promise2
setTimeout
以下分析建構執行上下文的過程
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
// 放進micro task queue等待執行
async function async2() {
console.log('async2');
}
// 放進micro task queue等待執行
console.log('script start');
// 發現同步任務執行的代碼以此這段先印出
setTimeout(function () {
console.log('setTimeout');
}, 0);
// 放進macro task queue等待執行
async1();
// 執行micro task queue
// console.log('async1 start'); 這段接著印出
// await async2(); 發現await關鍵字讓出執行緒處理async2()並暫停執行後面的代碼
// console.log('async2'); 這段接著印出並將執行緒還回去
new Promise(function (resolve) {
console.log('promise1');
resolve();
}).then(function () {
console.log('promise2');
});
// 接續console.log('async2');的執行結果
// 首先創建Promise發現建構式存在
// 於是接著印出console.log('promise1')
// 將then後面的函數放進macro task queue等待執行
// 此時micro task queue的內容:[console.log('async1 end'), console.log('promise2')]
// 以及macro task queue的內容:[console.log('setTimeout')]
// 沒有其他同步任務了開始清空queue
// 按照micro-> macro的順序
// console.log('async1 end') -> console.log('promise2') -> console.log('setTimeout')
直到看到下面的腦袋爆炸範例:
async function t1 () {
console.log(1)
console.log(2)
await new Promise(resolve => {
setTimeout(() => {
console.log('t1p')
resolve()
}, 1000)
})
await console.log(3)
console.log(4)
}
async function t2() {
console.log(5)
console.log(6)
await Promise.resolve().then(() => console.log('t2p'))
console.log(7)
console.log(8)
}
t1()
t2()
你可以正確地答出log順序嗎?
這概念真的滿不好用文字解釋的待補充
參考資料:
关于 Await、Promise 执行顺序差异问题
8张图帮你一步步看清 async/await 和 promise 的执行顺序
JS task到底是怎么运行的
Beware of the output when using @extend
when you want to DRY
,
you might be over engineering :(
Only use
@extend
when the rulesets that you are trying toDRY
out are inherently and thematically related.
Do not force relationships that do not exist: to do so will create unusual groupings in your project, as well as negatively impact the source order of your code.
Use a@mixin
to either inject dynamic values into repeated constructs or as a Sassy copy/paste which allows you to repeat the same group of declarations throughout your project while keeping a Single Source of Truth.-- csswizardry
git clone <remote_git_url> --branch <branch_name> --single-branch
cd new_repo
rm -rf .git/
git init
myrepo
under current working dir. And go into your cloned repo dir, remove all git config and cache under .git/, and re-initialize git.ref: https://stackoverflow.com/questions/1778088/how-do-i-clone-a-single-branch-in-git
ref: https://stackoverflow.com/questions/14969775/delete-all-git-commit-history
Like this one who build on Vue.js: https://weichiachang.github.io/ididnotsaythatshit/,
but build on React.js and further mock its end user interaction
<div className="form-group">
<label>{i18n.t('sdCard.basic.snapshotAmount')}</label>
<CustomTooltip show={!sdEnabled} title={i18n.t('sdCard.basic.enable')}>
<Field
disabled={formValues.sdEnabled === false || isWaitingApiCall}
name="snapshotMaxNumber"
type="number"
validate={emptyStringCheck}
placeholder="12000"
className={classNames('form-control', {'is-invalid': errors.snapshotMaxNumber && touched.snapshotMaxNumber})}
/>
</CustomTooltip>
<ErrorMessage component="div" name="snapshotMaxNumber" className="invalid-feedback"/>
<p className="text-size-14 text-muted mt-2">{i18n.t('sdCard.basic.snapshotRange')}</p>
</div>
CustomTooltip
as a direct parent of Field
, According to the source code, overlaytrigger will assign onFocus
and onBlur
to make show and hide works which is also the event that make formik touched works.onBlur
and cause the problem.note. CustomTooltip
uses props.children
to render components so the nearest parent element with closing tag will be <div className="form-group">
<CustomTooltip show={!sdEnabled} title={i18n.t('sdCard.basic.enable')}>
<div className="form-group">
<label>{i18n.t('sdCard.basic.snapshotAmount')}</label>
<Field
disabled={formValues.sdEnabled === false || isWaitingApiCall}
name="snapshotMaxNumber"
type="number"
validate={emptyStringCheck}
placeholder="12000"
className={classNames('form-control', {'is-invalid': errors.snapshotMaxNumber && touched.snapshotMaxNumber})}
/>
<ErrorMessage component="div" name="snapshotMaxNumber" className="invalid-feedback"/>
<p className="text-size-14 text-muted mt-2">{i18n.t('sdCard.basic.snapshotRange')}</p>
</div>
</CustomTooltip>
我們知道在專案中第一次push到遠端時候可以加入 --set-upstream / -u 讓git追蹤這個分支
git push -u origin master
之後要push就不必再加後面的參數
直接下git push
即可
那麼如果今天我們需要修改現有分支的名稱,該怎麼做呢?( github是不支援直接在網站上修改的 )
因此我們先刪除要改名的分支,在重新建立一個分支
git push <REMOTE_REPOSITORY> <SOURCE_BRANCH_NAME>:<DESTINY_BRANCH_NAME>
git push origin :remote_branch_to_delete
*<SOURCE_BRANCH_NAME>:<DESTINY_BRANCH_NAME>意思是將本地的SOURCE_BRANCH_NAME推到遠端的DESTINY_BRANCH_NAME
如果SOURCE_BRANCH_NAME在遠端分支中找不到的話就以SOURCE_BRANCH_NAME為分支名稱推到遠端的DESTINY_BRANCH_NAME
利用這個特性我們可以把SOURCE_BRANCH_NAME留空
那麼git就會將空白的名字推到遠端的DESTINY_BRANCH_NAME
也就是刪除掉這個分支
ref: https://git-scm.com/docs/git-push#OPTIONS
git branch -d branch_to_delete
指令會把 已經完成合併的分支 刪除,如果該分支有尚未合併的工作則會報錯
error: The branch 'branch_to_delete' is not fully merged.
If you are sure you want to delete it, run 'git branch -D branch_to_delete'.
因此這邊分成兩個狀況:該分支是否完成合併,可以下git branch --no-merged
來檢查尚未完成合併的分支,
最後從錯誤訊息可以知道這裡也有強制的選項,也就是-D
,如果真的確定不需要這些動作就可以直接強制刪除分支
git branch -m new_branch
這個就沒什麼特別就是把當前branch名稱改為new_branch
另外這個建立完後不會移動分支
必須下git checkout new_branch
才會移動至新分支
要直接在建立完之後移動至該分支的話可以下git checkout -b new_branch
git push origin -u new_branch
記住這邊一樣要使用第一次push用的指令組合
這樣git才會更新refs
否則直接下git push
會看到fatal: The upstream branch of your current branch does not match the name of your current branch.
可以下git branch -vv
或是git show-ref
查看目前分支設定
git add directory_or_file
會將選定的目錄或檔案加進提交暫存區(stage)
加進去後才可下git commit
提交修改
directory_or_file可以是當前目錄git add .
或者是特定子目錄git add path/to/dir/.
yarn
is different between yarn install
, yarn install
will install all dev/peer dependencies while yarn
won'tFeature:
ref:
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.