Preact-cli: Support async/await by default?

Created on 22 May 2017  路  29Comments  路  Source: preactjs/preact-cli

Hi,
is preact-cli support async await function?

thanks

help wanted

Most helpful comment

Update: I've released preact-cli-plugin-async, which brings optimized async/await support to Preact CLI via Kneden. We'll probably look at merging this into core, but for now it's the best way forward!

All 29 comments

Hiya - Preact itself doesn't care, but I would actually really like to support it as part of preact-cli's babel configuration. Ideally we could use something like babel-plugin-transform-async-to-promises to keep the output clean and minimal.

If anyone is looking to take on this issue, we'll need to circumvent ending up with Regenerator's runtime in the output (which is the default babel behavior). It's around 12kb, which would be a 50%+ size increase for lots of people.

Does babel-plugin-transform-async-to-promises also add runtime generator code?

@developit babel-plugin-transform-async-to-promises seems to be adding a minimal code of 45 bytes. Will we be up for taking it as a trade-off. or should this be same plugin kind as we discussed for lo-dash?

babel-plugin-transform-async-to-promises is currently unmaintained, and by own experience i can say that it often produces unexpected behaviour. Another option I've been looking at is fast-async. It uses nodent under the hood and can compile async functions to promises as well (if properly configured) without the need for a runtime.

+1 for fast-async, especially if we can make it opt-in. I haven't done enough testing of async-to-promises but the lack of a maintainer is mildly concerning.

@developit how about a plugin for this? or are you thinking a flag?

I tried to configure fast-async with preact.config.js:

export default (config, env, helpers) => {
  let { rule } = helpers.getLoadersByName(config, 'babel-loader')[0];
  let babelConfig = rule.options;

  babelConfig.plugins.push(['fast-async', {
    spec: true
  }]);
};

And npm run build throws an error:

> preact build
bundle.96daf.js from UglifyJs
Unexpected token operator 芦*禄, expected punc 芦(禄 [./index.js:4,0][bundle.96daf.js:607,39]
Build failed!

Any suggestions on how to make this work?
Full code here: https://github.com/yavorski/preact-cli-fast-async
Plugin for this would be nice though :)

I'm having the same issue as @yavorski . Without any configuration (fast-async or otherwise), preact-cli works fine in the development server mode, but build throws the same error.

@pbfy0 The issue occurs when there are untranspiled async functions, await expressions or generators in the resulting bundle - uglify-js can't handle these. In development we don't run uglify.

But as far as i can tell, the async functions are getting transpiled. If I disable source maps in Chrome on the development server, I don't see any async/await.

@yavorski preact-cli is using babel-preset-env, which would trigger built-in transform-async-to-generator for the preact-cli default browserlist. That is why you saw "*".

As async/await has natively been supported in Chrome, we override preact-cli default browserlist to just chrome. Then transform-async-to-generator won't be triggered and then we can use fast-async. However, for browser chrome, babel-preset-env won't transpile ES6 (such as class), which still causes issue for uglify-js.

babel/babel-preset-env#360

a little bit further analysis to introduce fast-async with preact-cli,

export default (env, options={}) => {
    const isProd = env && env.production;

    return {
        babelrc: false,
        presets: [
            [require.resolve('babel-preset-env'), {
                loose: true,
                uglify: true,
                modules: options.modules || false,
                targets: {
                    browsers: options.browsers
                },
                exclude: [
                    'transform-regenerator',
                    'transform-es2015-typeof-symbol'
                ]
            }],
            require.resolve('babel-preset-stage-1')
        ],
        plugins: [
            require.resolve('babel-plugin-transform-object-assign'),
            require.resolve('babel-plugin-transform-decorators-legacy'),
            require.resolve('babel-plugin-transform-react-constant-elements'),
            isProd ? require.resolve('babel-plugin-transform-react-remove-prop-types') : null,
            [require.resolve('babel-plugin-transform-react-jsx'), { pragma: 'h' }],
            [require.resolve('babel-plugin-jsx-pragmatic'), {
                module: 'preact',
                export: 'h',
                import: 'h'
            }]
        ].filter(Boolean)
    };
};

We could exclude 'transform-async-to-generator' from babel-preset-env and then add fast-async as one of the plugins. However, the above babel config inside preact-cli also include 'babel-preset-stage-1'. There is no way to exclude 'transform-async-to-generator' as it is part of 'babel-preset-stage-3'.

If we want to take 'babel-preset-stage-1' out of preact-cli, we need to identify each babel feature we would keep for preact-cli and then exclude 'transform-async-to-generator'. However, such practice seems to better any each project level not at preact-cli as current preact-cli is supporting changing babel configuration through preact.config.js. Any thoughts on this?

Is that finally solved? All worked fine in dev so I've converted my thunks to async/await. Then I ran a production build and caught the same asterisk error from uglify. Now I really don't want to revert as the code looks so clean. Looks like I must dig into and help to find a solution?

Why not drop UglifyJs and switch into Babili for code minify?

for anyone interested in using fast-async here is the way to do it:

export default (config, env, helpers) => {
  const { rule } = helpers.getLoadersByName(config, "babel-loader")[0];
  const babelConfig = rule.options;

  babelConfig.plugins.push([
    "fast-async",
    { compiler: { promises: true, noRuntime: true } }
  ]);
};

@malbernaz where are you placing that file? I ended up making my own .babelrc from the js-generated one in babel-config.js and adding the fast-async bit you suggested above, though I'm still getting the same UglifyJs error.

Why not drop UglifyJs and switch into Babili for code minify?

I'm wondering that as well -- if it's the case that UglifyJs doesn't handle ES6 code, doesn't that require every preact-cli project to be transpiled to ES5?

@timwis preact.config.js

Oh wow, totally missed that in the readme! Thanks, looks handy

@jchbh-duplicate / @malbernaz - Dropping uglify would remove the error, yes, but it would also result in the build containing async/await code, which would only run in very very recent browser builds. Currently we transpile everything to ES5, since that gives the best performance and compatibility.

@developit Including fast-async with the preact.config.js as I pointed out above works like a charm. No need to disable uglify...

Yup, was just late to reply. I think we should include it by default, ~and we should also include the babel configuration that disables regenerator~ (edit: that's the default).

@malbernaz I put that block in a new preact.config.js file in the root directory of my project, installed fast-async as a devdependency, and I'm still getting the same uglify error about unexpected token operator *. Is there some other step I'm missing?

Update: I've released preact-cli-plugin-async, which brings optimized async/await support to Preact CLI via Kneden. We'll probably look at merging this into core, but for now it's the best way forward!

Came here to post the same. 馃帀


Closing for now because solved -- can reopen when we reevaluate its inclusion into core.

preact-cli-plugin-async does not really work for me both on preact-cli and preact-cli@next. In both (widget template) I've got:

TypeError: Cannot read property 'push' of undefined

Neither any fast-async snippets in this issue work for me.

As in @developit dist at https://gist.github.com/developit/08acd182a30e66eda8de01dbbe9725ba there is same issue. Is there any workaround to make it work?

preact-cli@next has fast async enabled by default

Make sure to override after generating the template, because it still had the normal version in the dev dependencies

Make sure to override after generating the template, because it still had the normal version in the dev dependencies

What does it means? I tried preact-cli@next couldn't make async await work. Thanks

after you've generated the project, run npm i -D preact-cli@next, also don't put anything in preact.config.js

Was this page helpful?
0 / 5 - 0 ratings