sveltejs / svelte

Cybernetically enhanced web apps
https://svelte.dev
MIT License
78.19k stars 4.09k forks source link

Babel/Buble transformation doesn't appear to work. #717

Closed antony closed 7 years ago

antony commented 7 years ago

I've got a feeling that somewhere in the stack of svelte/rollup/babel, something has broken quite severely. I'm not sure exactly where, but I'm seeing it here (with all three combined), so I'm raising it here.

I'm noticing that in my production components, the ES6 code inside the svelte components is not being converted to ES5 by babel.

The problem can be reproduced by looking at the svelte examples, which also has an issue raised about this: https://github.com/charpeni/svelte-example/issues/8

Has something changed recently where babel can no longer transform the javascript code in a svelte component?

This issue is quite severe since it means maybe half, maybe more, of our users get a broken experience now as their browser is trying to run ES6.

I note there is also a note about using babel/buble in the code but this doesn't really explain how to do it, just that you should.

Rich-Harris commented 7 years ago

You just need to put the buble or babel plugin after the svelte plugin — the Svelte transformation needs to happen first, so that subsequent transformations are operating on JavaScript rather than Svelte templates.

antony commented 7 years ago

Ah - that's great. Works a treat, you're a life saver!

So perhaps I'll write some docs on this and open a PR.

Cheers

niahoo commented 6 years ago

Hey,

I'm trying to make it work nowadays, and the webpack configuration states that loaders are evaluated right to left.

So if I put babel-loader after svelte-loader, I have the following error:

ERROR in ./src/Somefile.html
Module build failed (from ./node_modules/babel-loader/lib/index.js):
SyntaxError: C:/...project/src/Somefile.html: Unexpected character '#' (1:1)

> 1 | {#if isVisible}
    |  ^
  2 |   <KeyboardEvents on:keyup="onkeyup(event)"/>
  3 | {/if}
  4 | <svelte:window`

But if I put babel-loader before svelte-loader, the ES6 code that I put in my components is not converted to ES5.

kaisermann commented 6 years ago

@niahoo What's your webpack rules config? You can use it like this:

{
    test: /\.(html|svelte)$/,
    use: [loaders.babel, loaders.svelte],
}
niahoo commented 6 years ago

Yes, something like that:

module: {
        rules: [{
            test: /\.js$/,
            exclude: /node_modules/,
            use: 'babel-loader',
        }, {
            test: /\.html$/,
            exclude: /node_modules/,
            use: [{
                loader: 'babel-loader'
            }, {
                loader: 'svelte-loader',
                options: {
                    skipIntroByDefault: true,
                    nestedTransitions: true,
                    emitCss: true,
                    hotReload: true
                }
            }]
        }, 

Babel preset is “env". I tried vvrious options, arrow fuctions are never transpiled.

(Btw don't worry for this, on my latest commit I was so frustrated I just removed babel and added a simple bublé command as a build step, for production only, outside of webpack - I'm so fed up with webpack/babel at the moment for multiples reasons on multiple projects …)

MarSoft commented 6 years ago

Also notice that at least for rollup-plugin-babel, you will have to explicitly configure it to handle Svelte's components as they are recognized from their original extension. So add something like extensions: ['.js', '.html', '.svelte'] when enabling Babel.

niahoo commented 6 years ago

Thanks for the tip !

simeydotme commented 5 years ago

to build on top of @MarSoft;

In Svelte3 I've found that you need to use [ ".js", ".mjs", ".html", ".svelte" ] and also remove the `exclude: "node_modules/"** so it can transpile the Svelte3 compiler bootstrap which is written in.mjs`

I also found that the .babelrc way of handling config will not work, as it treats each node module as handling it's own config. This basically means that the Svelte3 code wont transpile. So the approach to take is using a babel.config.js file in the root directory.

I've tried to document how I got transpiling working on the Svelte3 REPL (with rollup) here; http://simey.me/svelte3-rollup-and-babel7/#justcode

Hope this helps.

bgreater commented 5 years ago

@simeydotme I followed your instructions to the letter but I still can't get svelte + babel + rollup to transform all the js.

My structure looks like this:

video-app/
--babel.config.js
--package.json
--rollup.config.js
--src/
----main.js
----App.svelte

It's a very simple app but promises aren't being polyfilled and other syntax is erroring in ie11.

My package.json, babel.config.js and rollup.config.js are exactly the same as your blog post.

kaisermann commented 5 years ago

@bgreater @babel/preset-env won't automatically polyfill your code if you doesn't set the useBuiltIns property.

simeydotme commented 5 years ago

@simeydotme I followed your instructions to the letter but I still can't get svelte + babel + rollup to transform all the js. [...] It's a very simple app but promises aren't being polyfilled and other syntax is erroring in ie11. My package.json, babel.config.js and rollup.config.js are exactly the same as your blog post.

Hey, @bgreater are your other code (non-promise) being polyfilled? (eg: =>, let, const) as I didn't have any promises in my code when I came up with that... I can add a promise and experiment a bit more :)

dipscom commented 5 years ago

To cime in the exchange between @simeydotme and @bgreater - I am working on a project that requires IE11 support. The steps explained above were a great start but, like already metioned, there are other stuff that required polyfilling. In my case I came across this little not nice surprise.

After adding more polyfills than I care to count, my project now runs in IE11.

benjazehr commented 5 years ago

Actually @dipscom I had exactly the same requirement. As I did not find much online, I wrote this blogpost about how I solved it. The trick is to add es6-shim or core-js for polyfilling. I recommend working with the latter (and babel). My rollup config now looks like this:

import babel from 'rollup-plugin-babel';

export default {
  …
  plugins: [
    …,
    // compile to good old IE11 compatible ES5
    babel({
      extensions: [ '.js', '.mjs', '.html', '.svelte' ],
      runtimeHelpers: true,
      exclude: [ 'node_modules/@babel/**' ],
      presets: [
        [
          '@babel/preset-env',
          {
            targets: '> 0.25%, not dead',
            useBuiltIns: 'usage',
            corejs: 3
          }
        ]
      ],
      plugins: [
        '@babel/plugin-syntax-dynamic-import',
        [
          '@babel/plugin-transform-runtime',
          {
            useESModules: true
          }
        ]
      ]
    }),
    production && terser()
  ],
  …
}

I acutally copied this from sapper. Make sure you add babel or bublé before the terser.

pablote commented 5 years ago

I can't seem to make the suggested changes to work using rollup and babel. My web "works" with the below config, although I can see js code within svelte component not getting transpiled (There's async/await in the bundle).

The moment I add .svelte to babel's extension, things break:

Screen Shot 2019-06-20 at 22 55 27 Screen Shot 2019-06-20 at 22 55 38

If I remover terser the output changes a bit:

Screen Shot 2019-06-20 at 22 59 02

Anything else I try, removing babel's exclude, using babel.config.js as simeydotme's blog post doesn't help.

Anyone else run into this issue? thanks for the help.

rollup.config.js:

import svelte from 'rollup-plugin-svelte';
import babel from 'rollup-plugin-babel';
import resolve from 'rollup-plugin-node-resolve';
import commonjs from 'rollup-plugin-commonjs';
import livereload from 'rollup-plugin-livereload';
import {terser} from 'rollup-plugin-terser';
import visualizer from 'rollup-plugin-visualizer';
import sass from 'rollup-plugin-sass';
import autoprefixer from 'autoprefixer';
import cssnano from 'cssnano';
import postcss from 'postcss';

const production = !process.env.ROLLUP_WATCH;

export default {
    input: 'src/main.js',
    output: {
        sourcemap: true,
        format: 'iife',
        name: 'app',
        file: 'public/bundle.js'
    },
    plugins: [
        sass({
            output: 'public/bundle.global.css',
            processor: css => postcss([autoprefixer, cssnano({
                preset: ['default', {
                    discardComments: {
                        removeAll: true,
                    },
                }]
            })])
                .process(css, { from: undefined })
                .then(result => result.css)
        }),
        svelte({
            // enable run-time checks when not in production
            dev: !production,
            // we'll extract any component CSS out into
            // a separate file — better for performance
            css: css => {
                css.write('public/bundle.css');
            },
            onwarn: (warning, handler) => {
                if (warning.code === 'a11y-autofocus') return;
                handler(warning);
            }
        }),
        babel({
            exclude: 'node_modules/**'
        }),
        // If you have external dependencies installed from
        // npm, you'll most likely need these plugins. In
        // some cases you'll need additional configuration —
        // consult the documentation for details:
        // https://github.com/rollup/rollup-plugin-commonjs
        resolve(),
        commonjs(),

        // Watch the `public` directory and refresh the
        // browser on changes when not in production
        !production && livereload('public'),

        // If we're building for production (npm run build
        // instead of npm run dev), minify
        production && terser(),

        production && visualizer({
            filename: 'stats.html',
            open: true
        }),
    ]
};

.babelrc

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": "> 0.25%, not dead",
        "useBuiltIns": "entry",
        "corejs": 3
      }
    ]
  ]
}
mrkishi commented 5 years ago

@pablote Don't exclude svelte/internal from babel.

algorist-mechanism commented 5 years ago

Here is something that tripped me up with svelte 3 and babel-loader. It's related to the thread, so I'm putting it here, in the hopes it will help others. (I suspect it's because babel-loader wasn't picking up the svelte module and compiled file which are *.mjs files, but am not positive on that.)

After setting

extensions: ['.wasm', '.mjs', '.js', '.html', '.json', '.svelte'],
mainFields: ['svelte', 'browser', 'module', 'main'],

I found I had to change

rules: [
{
    test: /\.js$/,
    use: 'babel-loader',
},
{
    test: /\.svelte$/,
    use: [
        {loader: 'babel-loader}', 
        {loader: 'svelte-loader', options:{emitCss:true, }, 
    ],
    //omitted non relevant sections...
}]

to

rules: [
{
    test: /\.m?js$/,    //<--- key change here
    use: 'babel-loader',
},
{
    test: /\.svelte$/,
    use: [
        {loader: 'babel-loader}', 
        {loader: 'svelte-loader', options:{emitCss:true, }, 
    ],
    //omitted non relevant sections...
}]

to get webpack 4 to bundle the svelte files properly.

getkey commented 5 years ago

I had the same issue as @pablote. My solution was to change my Babel include to include: ['src/**', 'node_modules/svelte/**'],. Full config:

babel({
    extensions: ['.js', '.jsx', '.es6', '.es', '.mjs', '.svelte'], // https://github.com/sveltejs/svelte/issues/717#issuecomment-417422146
    include: ['src/**', 'node_modules/svelte/**'],
    presets: [
        ['@babel/preset-env', {
            useBuiltIns: 'usage',
            corejs: 3,
        }],
    ],
    plugins: [
        '@babel/plugin-proposal-object-rest-spread',
    ],
}),