disable the macos auto update notification

The auto update notification is pretty annoying since it popup everyday, and you need several clicks to make it disappear.

xmac-update-automatic

change from UI

I tried to disable it from System Preference -> App Store -> uncheck Automatically check for update. it does not that the checkbox keep checked after i reopen the system preference panel.

enable-or-disable-auto-apps-update-on-mac

Solution

Have to do it from command line via sudo.

	sudo ​softwareupdate --schedule off
	sudo defaults write /Library/Preferences/com.apple.SoftwareUpdate AutomaticCheckEnabled -bool FALSE

You can view the status by running
sudo defaults read /Library/Preferences/com.apple.SoftwareUpdate

Advertisements

React Native on a machine 8081 occupied

Today, as i was setting up a basic React native app on my company’s laptop, I cannot run the RN packager server which is default to port 8081​. I ran the lsof -i :8081 but get nothing. Turns out I have to run it with sudo because the app that uses this port is the Corporate Mcafee.

Ideally i do not want to uninstall/unload Mcafee unless I have to, try to find a work around first . (For iOS, as of Sep/2017, I did not find a way for RN​ to work on a custom port, so have to unload McAfee, which is unfortunate.)

First thing to do is to run the packager server in a different port:

react-native start --port 8088

And now the packager server is up and running. However when i run react-native run-android , it still tells me JS server not recognized , so to get rid of this msg, i have to change some source code in the node module. The logic is in node_modules/react-native/local-cli/util/isPackagerRunning.js, and we just need to change the port in the fetch function from 8081 to the 8088 that we use above.

Now the android app should be able to be installed in the virtual device and run. However we still could not leverage the live reload capability of RN because if we double click r to reload, we get a red screen saying cannot connect to 10.0.2.2:8081. This is because when we use Genymotion virtual device, the code in node_modules/react-native/ReactAndroid/src/main/java/com/facebook/react/modules/systeminfo/AndroidInfoHelpers.java will return that url. So we need to cmd+M in the emulator, Go to Dev Settings → Debug server host for device, enter ‘localhost:8081’. 

This is to overwrite the emulator’s debug server.(NOTE: if you are connecting your REAL android device, you do not have to change the above host).  Now we have the last step which is to forward the request in our local VD’s 8088 port to our machine’s 8088 port which runs the packager server by doing:

adb reverse tcp:8088 tcp:8088

The first part is VD and 2nd one is for the hosting machine. More about adb reverse. (Note: even for the VD, try to avoid using 8081. It would work for normal development/reload, but will not work with chrome remote debugging which still forwards the http request for index.android.bundle  to the host’s 8081 which is used by Mcafee.)

Now you should be able to change your index.android.js and hit r twice or cmd+M -> Reload to reload the VD.

webpack custom plugin

Recently we work with a platform which need to use webpack to build some ng2/4 assets and also some custom steps to pull data from a headless cms(via gulp) and eventually render components. One problem here is we cannot do live reload/recompile that every time we make some change we have to run the npm command again to compile the resources.

To solve the issue, i decided to write a custom webpack plugin to make browser-sync and webpack work together.

The basic flow is 1. run webpack in watch mode so every time a resouce(ts/css/html) changes, webpack auto re-compile, 2. serve the resources via browser-sync, here browserSync just serve as a mini express server and provide browser reload capability. 3. a webpack plugin to start the browser-sync server and register the reload event when webpack compilation is done.

Plugin

The webpack api is pretty straightforward, it exposes a compile object from the plugin’s apply function. It represents the fully configured Webpack environment. This object is built once upon starting Webpack, and is configured with all operational settings including options, loaders, and plugins. When applying a plugin to the Webpack environment, the plugin will receive a reference to this compiler. Use the compiler to access the main Webpack environment.

const browserSync = require('browser-sync');

function WebpackAndromedaPlugin(options) {
  console.log(`WebpackAndromedaPlugin options: ${JSON.stringify(options, null, 2)}`);

  let browserSyncConfig = require('./lib/dev-server').getBrowserSyncConfig(options);
  browserSyncConfig.server.middleware.push(require('./lib/dev-server').makeServeOnDemandMiddleware(options));
  browserSync.init(browserSyncConfig);
}

WebpackAndromedaPlugin.prototype.apply = (compiler) => {

  compiler.plugin("compile", function (params) {
    console.log('--->>> andromeda started compiling');
  });

  compiler.plugin('after-emit', (_compilation, callback) => {
    console.log('--->>> files prepared');
    browserSync.reload();
    callback();
  });
}

as we can see above, we can register our callbacks with compiler.pulgin(), where webpack exposes different stages for us to interact.

Another important object is compilation, which  represents a single build of versioned assets. While running Webpack development middleware, a new compilation will be created each time a file change is detected, thus generating a new set of compiled assets. A compilation surfaces information about the present state of module resources, compiled assets, changed files, and watched dependencies. The compilation also provides many callback points at which a plugin may choose to perform custom actions.

For example, all the generated files will be in compilation.assets object.

webpack-dev-middleware

The webpack-dev-middleware is a nice little express middleware that serves the files emitted from webpack over a connect server. One good feature it has is serving files from memory since it uses a in memory file system, which exposes some simple methods to read/write/check-existence in its MemoryFileSystem.js.  The webpack-dev-middleware also exposes some hooks like close/waitUntilValid etc, unfortunately the callback that waitUntilValid registers will only be called once according to the compileDone function here. Anyway, it is still an efficient tool to serve webpack resources and very easy to integrate with the webpack nodejs APIs:

~function() {
  const options = require('./config');
  let  webpackMiddleware = require("webpack-dev-middleware");

  let webpack = require('webpack');
  let browserSyncConfig = getBrowserSyncConfig(options);
  browserSyncConfig.server.middleware.push(makeServeOnDemandMiddleware(options));
  const compiler = webpack(require('./webpack.dev'));
  compiler.plugin('done', ()=>browserSync.reload())
  let inMemoryServer = webpackMiddleware(compiler, {noInfo: true, publicPath:'/assets'});
  browserSyncConfig.server.middleware.push(inMemoryServer);
  browserSync.init(browserSyncConfig);
}();

 

webpack-dev-server

The webpack-dev-server is basically a wrapper over the above webpack-dev-middleware. it is good for simple resources serving since it does not expose much. I was trying to find a hook to it to intercept the resource it generates/serves but did not get a good solution. If you need more customization, it would be better to go with webpack-dev-middleware.

a very detailed webpack intro article

polygon in svg and css

in svg we can create triangle like below

<svg height="210" width="500">
  <polygon points="200,10 250,195 160,210" style="fill:lime;stroke:purple;stroke-width:1" />
  Sorry, your browser does not support inline SVG.
</svg>

turns out in css, we have similar stuff called clip-path which take similar parameter and draw the shape.

clip-path: polygon(50% 0%, 0% 100%, 100% 100%);

For circle/ellipse, it has specific function, circle and ellipse.

We can do something like

clip-path: circle(50% at 50% 50%);
Or
clip-path: circle(50px at 50px 50px) means at(50px, 50px),clip a circle with radius 50px.

More example here.

Or a 中文文章

debug hover item in chrome devtools

Chrome devtools is our friend, always.

Today when I was developing an angular 4.x app with primeng library, i have to check the class set on the tooltip component. As we know the tooltip is hover event based, so if we hover on it to make it showup and then shift our focus to the dev tool element tab, the tooptip would disappear.

Chrome tool has a feature to activate the hover stuff(:hover) on specific element for CSS sake. It is quite handy but obviously it does not apply in this use case since this tooltip is js based.

Search around and finally find a solution: using F8 or CMD + \ which is pause the script execution.

Steps are quite straightforward:

Mouse over the tooltip, and press F8 while it is displayed.

Now you can now use the inspector to look at the CSS.

A deeper look at event loop (micro/macro tasks)

One common question

(function test() {
    setTimeout(function() {console.log(4)}, 0);
    new Promise(function executor(resolve) {
        console.log(1);
        for( var i=0 ; i<10000 ; i++ ) {
            i == 9999 && resolve();
        }
        console.log(2);
    }).then(function() {
        console.log(5);
    });
    console.log(3);
})()

So why the result is 1,2,3,5,4 rather than 1,2,3,4,5

If we look at the detail, looks like the async of setTimeout is different from the async of Promise.then, at least they are not in the same async queue.

The answer is here in the whatwg SPEC.

  • An event loop has one or more task queues.(task queue is macrotask queue)
  • Each event loop has a microtask queue.
  • task queue = macrotask queue != microtask queue
  • a task may be pushed into macrotask queue,or microtask queue
  • when a task is pushed into a queue(micro/macro),we mean preparing work is finished,so the task can be executed now.

And the event loop process model is as follows:

when call stack is empty,do the steps-

  1. select the oldest task(task A) in task queues
  2. if task A is null(means task queues is empty),jump to step 6
  3. set “currently running task” to “task A”
  4. run “task A”(means run the callback function)
  5. set “currently running task” to null,remove “task A”
  6. perform microtask queue
    • (a).select the oldest task(task x) in microtask queue
    • (b).if task x is null(means microtask queues is empty),jump to step (g)
    • (c).set “currently running task” to “task x”
    • (d).run “task x”
    • (e).set “currently running task” to null,remove “task x”
    • (f).select next oldest task in microtask queue,jump to step(b)
    • (g).finish microtask queue;
  7. jump to step 1.

a simplified process model is as follows:

  1. run the oldest task in macrotask queue,then remove it.
  2. run all available tasks in microtask queue,then remove them.
  3. next round:run next task in macrotask queue(jump step 2)

something to remember:

  1. when a task (in macrotask queue) is running,new events may be registered.So new tasks may be created.Below are two new created tasks:
    • promiseA.then()’s callback is a task
      • promiseA is resolved/rejected:  the task will be pushed into microtask queue in current round of event loop.
      • promiseA is pending:  the task will be pushed into microtask queue in the future round of event loop(may be next round)
    • setTimeout(callback,n)’s callback is a task,and will be pushed into macrotask queue,even n is 0;
  2. task in microtask queue will be run in the current round,while task in macrotask queue has to wait for next round of event loop.
  3. we all know callback of “click”,”scroll”,”ajax”,”setTimeout”… are tasks,however we should also remember js codes as a whole in script tag is a task(a macrotask) too.

 

In nodejs world:  setImmediate()is macro/task, and process.nextTick() is a micro/job

 

One good discussion in Chinese and blog.

clipboard in terminal(copy/paste)

Was watching a CD video with Semaphore and saw the guy in the video manipulating clipboard with pipe directly in the terminal. Pretty cool! Did some research on that.

OSX(MacOS)

In Mac, it is pretty straightforward with the built in pbcopy and pbpaste. (pasteboard copy / paste). Some examples:

cat my.key.pub | pbcopy

pbpaste > my.otherKey.pub

ps aux | grep myKeyWord | pbcopy

pbcopy < file.txt

pbpaste | grep myKeyWord

Linux

Take Ubuntu as example here. We can install a 16 kB program called xclip:

sudo apt-get install -y xclip

Then we can set alias so we can do the above operation like in osx. If you use bash then set your ~/.bashrc:

alias pbcopy='xclip -selection clipboard'
alias pbpaste='xclip -selection clipboard -o'

If you are like me using fish as main shell, then similarly add below to your ~/.config/fish/config.fish file.

alias pbcopy "xclip -selection clipboard"
alias pbpaste "xclip -selection clipboard -o"