Giter VIP home page Giter VIP logo

blog's People

Contributors

bensonliao avatar flameddd avatar

Stargazers

 avatar

Watchers

 avatar  avatar

blog's Issues

[Windows] How to run ssh agent in Powershell

Preface

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.

git ssh related setup

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,

  1. install posh-sshell
  2. add the following script to your shell profile (e.g. run notepad $PROFILE)
    Import-Module posh-git
    Import-Module posh-sshell
    Start-SshAgent
    
  3. and it should run the ssh-agent succesfully

ref

Git: 當stash存在多個時指定套用的stash

如果我們有多個暫存變動
想要指定套用特定的變動
可以在popapply指定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

How to optimize js start-up execution with Create-React-App and Web Workers ?

大多數的react開發者應該都知道CRA這個官方提供的開發工具吧~
優點是方便快速幾乎不用什麼設定就能開發好一個網頁應用程式,
但是相對的缺點也恰好就是:

不用什麼設定

因為CRA都幫你設定好了,但你也不能動lol

這代表假設要使用某些webpack-plugin / loader之類,
比如說今天要說的主題之一:worker-loader
或者是要自訂如何做code-splitting等等方式來優化都是沒辦法的。

當然如果你是webpack調教高手,我想這篇可以跳過了
這篇是給還在用CRA的新中老手們參考的,
OK~那麼本文開始!

Web Workers

談到前端優化,最近這東東似乎滿多人在討論的,
目前已知的優化方式包括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了嗎?

不,我們還有選擇!

CRA如何在不eject的情況下自定 webpack config?

答案是可以的!
使用工具: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')
})
  • 在要用到worker的元件如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)

audit_result_with_web_worker
具體步驟參考這篇跟留言遇到的錯誤情況作修正。
以上,如有謬誤歡迎補充或指正:)

How to remove local branches if they are merged into master?

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?

Update

Auto version

git config remote.origin.prune true.
https://stackoverflow.com/questions/18308535/automatic-prune-with-git-fetch-or-pull

Yes, there it is!!

Solutions

  1. With the following command combination:
    git branch --merged master | grep -v '^[ *]*master$' | xargs git branch -d

  2. 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).
    
  3. 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).
    

Explanation

And let's figure it out what those command do...

  1. git branch --merged master
    this commend will output only the merged branches to master branch, like:
      add-api-comments
    * master
      refactor-dev-code-structure
      update-dependencies
    
  2. grep -v '^[ *]*master$'
    this command will using regex to filter master branch from output
  3. 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 master

ref: StackOverflow
ref: xargs examples

Git本地分支名稱大小寫的二三事

Git ref其實是類似指標的結構,
在切換分支時其實git背後做了這樣的事: ln -sf refs/heads/newbranch .git/HEAD
所以假設在不區分大小寫的檔案系統上如OSX,
創了Bugfix的分支,
相當於建立了一個不區分大小寫的指標,
也就是bugfixBugfix都會指到同一個ref folder,
未來假設要創bugfix也會提示你已經存在,
但是在有區分大小寫的檔案系統中如Windows會有找不到指標的問題,
我們可以直接改.git/refs/heads的資料夾名稱來解決這樣的情況.

參考資料-ref是啥
參考資料-解決方案

How to undo/redo commit in Git?

When using Git, we sometimes do commit unintentionally or want to track and test on different version of codebase.

We can do it base on 3 commands: revert, rebase and reset

Let's quickly look at its description,

first are revert:

Revert some existing commits.

Given one or more existing commits, revert the changes that the related patches introduce, and record some new commits that record them. This requires your working tree to be clean (no modifications from the HEAD commit).

Here's a illustration about the behavior:

git_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:

Reapply commits on top of another base tip. Keep it mind that rebase are not rewrite history but append with it.

Here's 2 illustrations about the behavior:

git_rebase_before
git_rebase_after

reset:

Reset current HEAD to the specified state. There's 2 option to do reset, soft and hard. And as the name implies, the soft option are not actually delete those commit history while the hard does. So be carefully with the hard option, and the default option is soft.

Here's 2 illustrations about the behavior:

git_reset_soft
git_reset_hard

If you want to undo a commit other than the latest on a branch, git revert is your friend.

But if you want to test or restore on certain point of the entire codebase for a branch, use git rebase or git reset.

For test safety we should always create a new branch to do that.

  1. Create and copy from the branch we want to test: git branch test_branch
    1. (Optional) Or use git checkout -b test_branch to skip step 2.
  2. Switch to the branch we created: git checkout test_branch
  3. git rebase <sha1-id> or git reset --hard <sha1-id>
  4. That's it, we are good to test!

For restore a branch, skip the first 2 steps of course.

There are also have more parameter can be used, see https://git-scm.com/docs/gitrevisions

to be continue...

Eslint: set default level as warning

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" }
]

How to publish scope npm package

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:

  1. $ cd <you_package_repo>
  2. $ npm link
    note. 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
  3. $ cd <other_repo>
  4. $ npm i usr/local/lib/node_module/@scope-name/package-name
  5. test your package

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

NPM, note about install, uninstall and update

When we want not just install package into node_modules but also as dependencies in package.json,

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 )

When we want to remove package,

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`.

When we want to update the installed package,

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.

How to rewrite the commit history in Git?

As the blog #4 mentioned, none of those command are really do rewrite commit history.

And of course we can do with reset <commit-sha-id> --hard but it only do delete, what if we want to alter it?

Yes! git filter-branch

*Be careful about the so call nuclear-grade option

A general use case are to change committer information like author name or email:

git filter-branch -f --env-filter "if [[ \$GIT_AUTHOR_EMAIL = '[email protected]' ]]; then [email protected]; fi" HEAD

or git filter-branch -f --env-filter "if [[ \$GIT_AUTHOR_EMAIL = '[email protected]' ]]; then GIT_AUTHOR_NAME=myname; [email protected]; fi" HEAD

or git filter-branch -f --env-filter "if [[ \$GIT_AUTHOR_EMAIL = '[email protected]' ]]; then [email protected]; fi" HEAD

or whatever config you want to set.

Then if you run 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

So if you want to push to remote branch after one or more command, use 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.

Javascript destructuring function arguments

One of ECMAScript6 features is object destructuring.

If you aren't familiar with JavaScript destructuring,

it basically provides a shorter syntax for extracting an object key's value without the dot notation mess:

// A javascript object
const myObject = { x: 1, y: 2 };

// Destructuring
const { x, y } = myObject;
// x is 1, y is 2

The basic syntax for destructuring is fairly simple,

but using destructuring with function arguments can be a bit more difficult

when those argument values should have default values.

The following is a function with arguments having default values:

function myFunction(text = "", line = 0, truncate = 100) {

    // With default values, we can avoid a bunch of:
    text = text || "";
    line = line || 0;
    truncate = truncate || 100;
}

Regardless of language,

if a function takes more than 3 parameters,

it's probably best to pass in an object name options or config that contains possible key/values;

the equivalent would look like:

function myFunction(config) {

}

// Usage
myFunction({
    text: "Some value",
    line: 0,
    truncate: 100
})

What if you want to use destructuring in JavaScript function arguments though?

The following function signature would become:

function myFunction({ text, line, truncate }) {

}

If you want to define default values in the function configuration, you'd use the following:

function myFunction({ 
  text = "", 
  line = 0, 
  truncate = 100 
} = {}) {
 // Even if the passed in object is missing a given key, the default is used!
}

Setting a default with = {} is important, with no default the following example would throw an error:

TypeError: Cannot destructure property `key` of 'undefined' or 'null'

Destructuring is an awesome language feature but can lead to confusion and even errors.

Hopefully the basics provided in this guide can help you to navigate using JavaScript destructuring with functions!

Apply with React.js

It is useful for readability and make components more concise

Example without desctructuring syntax

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>
    );
  }
}

Example with desctructuring syntax, Hell yeah~!

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>
  )
}

區塊鍊界的Youtube !?

先放參考資料
https://www.bnext.com.tw/article/66831/odysee-in-taiwan
https://blog.simpleinfo.cc/shasha77/what-is-lbry

簡評

  • 去年剛成立就被LBRY收購,實力不容小覷
  • LBRY是一個開放原始碼去中心化的數字內容分享和交易平台,於2016年7月4日上線。搭建於此平台之上的影音分享網站lbry.tv和Odysee.com被視為傳統平台的替代品
  • lbry.tv似乎找不到網頁版了,不過畢竟是舊版現在應該是以Odysee.com為主
  • Odysee.com的界面確實跟YT很像,大概有87成像XD
  • 意外發現一些奇怪的行為像是要拖曳調整影片留言的文字輸入框大小結果放開後跳轉到登入頁,是故意的嗎?

Blog: NPM, how to install all the dependencies from a package ?

In some circumstances, you may encounter a problem when npm i <package-name> not automatically install all the dependencies that package require.

How do we manually install them? (of course not install them per line of command)

We can achieve by using 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:

  1. npm info react-scripts@latest dependencies
    list all dependencies for a package
  2. echo $(npm info react-scripts@latest dependencies)
    here's a tricky part for valid input stream feed to sed
  3. sed -E "s/,|\'|{ | }//g; s/: /@/g"
    because npm info will format the result, so we will use regex to clean format
  4. $(echo $(npm info react-scripts@latest dependencies) | sed -E "s/,|\'|{ | }//g; s/: /@/g")
    another tricky part for valid command argument to npm i

How to deploy Create React App project to github pages?

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:

  1. Following the official github pages to make your homepage at username.github.io
  2. Then github pages will lookup 3 locations for project-pages-sites to serve:
    1. master branch
    2. gh-pages branch
    3. a folder named "docs" located on the master branch
  3. After step.1, then the how-to-serve-on-github-pages will work, if you skip step.1 then you will see 404 of resource are not found errors.
  4. When step.1 and step.3 are done, how do we update the pages ? Simply run npm 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 :)

eslint rule如果已經deprecated要如何處理?

如果eslint中發現某個rule已經deprecated,該如何處理?

我們都知道eslint的好處

但是在這變化快速的時代

eslint所用的rule也常常更新

但有時候原作者是將舊rule標為deprecated而不是直接刪除

我們在安裝哪些plugin的時候就會一併將新舊rule一起裝進來了

這時候可能會在編輯器發現這樣的錯誤提示

new_rule_and_deprecated_rule_warnning_at_same_line_of_code

我們好奇這個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了:)

How to manage published npm packages on a new machine

Prerequisites:

  • a registered npm account
  • a published packages (of course)

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)

How to move to another branch and put aside working changes without losing it in Git?

  1. First, of course you can actually push changes to the remote and do git reset/revert/rebase or just change code onward.
  2. Using git stash to keep a stash of your working changes, a restore from it.
    There's some major situation when create and restore from stashes:
    note. in fact git can store more than 1 stash, git stash list will tell you the stashes you created
    note. so the following restore command are short-hand for the last stash you created, if you want to specify other stash, check doc
  • create stash to record only modified files
    git stash
  • create stash to record modified files include un-tracking files
    git stash -u
  • restore only un-staged changes
    git stash apply
  • restore only staged and un-staged changes (when you run git add <files_or_dirs>, those files or dirs will staged)
    git stash apply --index

Javascript ES6 Destructuring And React

One of ECMAScript6 features is object destructuring.

If you aren't familiar with JavaScript destructuring,

it basically provides a shorter syntax for extracting an object key's value without the dot notation mess:

// 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

The basic syntax for destructuring is fairly simple,

but using destructuring with function arguments can be a bit more difficult

when those argument values should have default values.

The following is a function with arguments having default values:

function myFunction(text = "", line = 0, truncate = 100) {

    // With default values, we can avoid a bunch of:
    text = text || "";
    line = line || 0;
    truncate = truncate || 100;
}

Regardless of language,

if a function takes more than 3 parameters,

it's probably best to pass in an object name options or config that contains possible key/values;

the equivalent would look like:

function myFunction(config) {

}

// Usage
myFunction({
    text: "Some value",
    line: 0,
    truncate: 100
})

What if you want to use destructuring in JavaScript function arguments though?

The following function signature would become:

function myFunction({ text, line, truncate }) {

}

If you want to define default values in the function configuration, you'd use the following:

function myFunction({ 
  text = "", 
  line = 0, 
  truncate = 100 
} = {}) {
 // Even if the passed in object is missing a given key, the default is used!
}

Setting a default with = {} is important, with no default the following example would throw an error:

TypeError: Cannot destructure property `key` of 'undefined' or 'null'

Destructuring is an awesome language feature but can lead to confusion and even errors.

Hopefully the basics provided in this guide can help you to navigate using JavaScript destructuring with functions!

Apply with React.js

It is useful for readability and make components more concise

Example without desctructuring syntax

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>
    );
  }
}

Example with destructuring syntax, Hell yeah~!

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>
  )
}

JS如何運行非同步任務的?

這概念老實說一直困擾著我,
很難真正理解跟內化,
尤其是前幾年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到底是怎么运行的

A guide for using @extend and/or @mixin

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 to DRY 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

when-to-use-extend-when-to-use-a-mixin

How to clone only a branch of remote repo and make a brand new repo in Git?

First, how do we clone just one branch of a remote repo?

git clone <remote_git_url> --branch <branch_name> --single-branch

fill in <remote_git_url> and <branch_name> for your own desire

Second, how do we make the cloned repo as a brand new one? (without any commit history and etc...)

cd new_repo
rm -rf .git/
git init

For example, if you clone https://github.com/user/myrepo.git git will create a dir call 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

A note for people who using react-boostrap's overlaytrigger with formik's field

When you want to using react-boostrap's overlaytrigger to create a tooltip on formik's field, be aware of the following situation

This is a normal formik fileld level error message ui:

normal-formik-validation-style

And this is something we don't expected:

missing-formik-validation-style

But why?

Here's the code:

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

And the problem was because we wrap our 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.

So if we wrap components like the above code does, the overlaytrigger will override formik's onBlur and cause the problem.

And the correct way, in this case, is to wrap field on a parent element like:

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>

git branch處理的一些心得

git branch改名的處理方式(包括本地與遠端同步)

我們知道在專案中第一次push到遠端時候可以加入 --set-upstream / -u 讓git追蹤這個分支

git push -u origin master

之後要push就不必再加後面的參數

直接下git push
即可

那麼如果今天我們需要修改現有分支的名稱,該怎麼做呢?( github是不支援直接在網站上修改的 )

因此我們先刪除要改名的分支,在重新建立一個分支

1.刪除遠端分支

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

1.2刪除本地分支

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,如果真的確定不需要這些動作就可以直接強制刪除分支

2.建立本地分支

git branch -m new_branch

這個就沒什麼特別就是把當前branch名稱改為new_branch

另外這個建立完後不會移動分支

必須下git checkout new_branch才會移動至新分支

要直接在建立完之後移動至該分支的話可以下git checkout -b new_branch

3.將新分支重新推到遠端

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指令說明

git add directory_or_file

會將選定的目錄或檔案加進提交暫存區(stage)

加進去後才可下git commit提交修改

directory_or_file可以是當前目錄git add .

或者是特定子目錄git add path/to/dir/.

Yarn install issue

  • env
    • yarn v1.22.17
  • issue
    • yarn is different between yarn install, yarn install will install all dev/peer dependencies while yarn won't

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.