Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Can't modify babel rule to exclude bootstrap in node_module #558

Open
ger86 opened this issue Apr 9, 2019 · 12 comments
Open

Can't modify babel rule to exclude bootstrap in node_module #558

ger86 opened this issue Apr 9, 2019 · 12 comments

Comments

@ger86
Copy link

ger86 commented Apr 9, 2019

Hi,

Last year I found a solution to allow Babel to process files in node_modules using something like this:

const webpackConfig = Encore.getWebpackConfig();
const babelLoader = webpackConfig.module.rules.find(rule => { 
  if (rule.use && rule.use[0]) {
    const firstUse = rule.use[0];
    return firstUse.loader === 'babel-loader';
  } 
  return false;
});
babelLoader.exclude = /node_modules\/(?!bootstrap\/).*/;
module.exports = webpackConfig;

But in the recent versions, when I run yarn run encore production I get the files from Bootstrap without being transpiled, which not happens in my regular files.

I am using the file babelrc to configure Babel:

{
    "presets": [
      [
        "@babel/preset-env",
        {
          "debug": true,
          "useBuiltIns": "usage",
          "corejs": 3,
          "targets": "> 0.25%, not dead"
        }
      ]
    ]
  }

The weird thing is that if I configure Babel through webpack.config.js:

  .configureBabel(function(babelConfig) {
   }, {
       include_node_modules: ['bootstrap']
   })

it works perfect. So I don't know the difference between the two solutions. Is there any implementation detail under this case that causes the first solution not valid (as I said, last year it works well)?

@ger86
Copy link
Author

ger86 commented Apr 9, 2019

Something more... if I copy the babel config from file babel.js to .babelrc:

{
  "presets": [
    [
      "@babel/preset-env",
      {
        "targets": {},
        "modules": false,
        "forceAllTransforms": true,
        "useBuiltIns": "entry"
      }
    ]
  ],
  "plugins": ["@babel/plugin-syntax-dynamic-import"]
}

It doesn't work neither. I have tried to replicate the logic of option include_node_modules in my webpack.config.js:

const webpackConfig = Encore.getWebpackConfig();
const babelLoader = webpackConfig.module.rules.find(rule => { 
  if (rule.use && rule.use[0]) {
    const firstUse = rule.use[0];
    return firstUse.loader === 'babel-loader';
  } 
  return false;
});
babelLoader.exclude = (filePath) => {
  if (!/(node_modules|bower_components)/.test(filePath)) {
      return false;
  }
  const whitelistedModules = ['bootstrap'].map(
      module => path.join('node_modules', module) + path.sep
  );

  for (const modulePath of whitelistedModules) {
      if (filePath.includes(modulePath)) {
          console.log('hi');
          return false;
      }
  }
  return true;
};
module.exports = webpackConfig;

The callback is executed when run yarn run encore production and returns false as expected but I still gets the spread operator in the resulting file that contains the Bootstrap code. However, if I use:

.configureBabel(function(babelConfig) {}, {
   include_node_modules: ['bootstrap']
})

it works as expected. I can't find the difference between the two methods so I think there is something in the middle that breaks my alternative when using the .babelrc file.

@stof
Copy link
Member

stof commented Apr 10, 2019

Note that in the latest version of Encore, you can now use the include_node_modules (well, its new name is includeNodeModules but include_node_modules still works with a deprecation warning) even when using an external babel config, by passing null as the first argument to configureBabel.

@ger86
Copy link
Author

ger86 commented Apr 10, 2019

Yeah, I know! But my question is about the difference in the two methods because it seems that using .babelrc file doesn't perform the same result as using the configureBabel method

@Lyrkan
Copy link
Collaborator

Lyrkan commented Apr 10, 2019

Hi @ger86,

I can't see any reason why it wouldn't work since the exclude rule is not handled by Babel but by Webpack itself.

I did a quick test with the following files and it seems to be fine:

// webpack.config.js
const Encore = require('@symfony/webpack-encore');

Encore
  .disableSingleRuntimeChunk()
  .setOutputPath('build/')
  .setPublicPath('/')
  .cleanupOutputBeforeBuild()
  .addEntry('main', './src/index.js')
;

const config = Encore.getWebpackConfig();

const babelLoader = config.module.rules.find(
  rule =>
    rule.use &&
    rule.use[0] &&
    rule.use[0].loader === 'babel-loader'
);

babelLoader.exclude = /node_modules\/(?!bootstrap\/).*/;

module.exports = config;
// src/index.js
require('bootstrap/js/src/popover.js');

Without the babelLoader.exclude = ... line:

$ fgrep -Rnil '...' ./build | wc -l
1

With it:

$ fgrep -Rnil '...' ./build | wc -l
0

Would you be able to share a repository that could show this issue?

@ger86
Copy link
Author

ger86 commented Apr 11, 2019

Sure, I will post a repository with the failing code this weekend. Thanks

@ger86
Copy link
Author

ger86 commented Apr 12, 2019

Hi,
I have created a repo: https://github.com/ger86/webpackencore-babel with my config and the steps to reproduce in the Readme.md.

As you will see, when there is a .babelrc file, you get the spread operator in the resulting file.
I would love to know the explanation of what is happening because I have been unable to find it after many hours.

Thanks

@Lyrkan
Copy link
Collaborator

Lyrkan commented Apr 12, 2019

@ger86 I think that the exclude rule isn't actually the issue.

No matter which one of the config listed in your webpack.config.jsyou are using, Babel do process Bootstrap's files.

However, it doesn't do it with the same config than the one used for your files:

  • without the .babelrc file it uses the configuration provided by Encore, which applies project-wide
  • with the .babelrc you are using a file-relative configuration which only applies to the current package... and not to Bootstrap (Babel would use its .babelrc if it had one).

As noted on the following page a babel.config.js file should work better in your case: https://babeljs.io/docs/en/configuration#what-s-your-use-case

@Johann-S
Copy link

Hi @ger86,

Just a simple question, what's your need to transpile Bootstrap source code, when you can only include what you need of Bootstrap thanks to the files in js/dist.
The files in the js/dist are already transpiled separately

import 'bootstrap/js/dist/dropdown'

@Lyrkan
Copy link
Collaborator

Lyrkan commented Apr 12, 2019

@Johann-S Not sure how useful it would be (if at all), but one possible use-case would be to use their own targets instead of the ones used during Bootstrap's release process.

@ger86
Copy link
Author

ger86 commented Apr 16, 2019

@ger86 I think that the exclude rule isn't actually the issue.

No matter which one of the config listed in your webpack.config.jsyou are using, Babel do process Bootstrap's files.

However, it doesn't do it with the same config than the one used for your files:

  • without the .babelrc file it uses the configuration provided by Encore, which applies project-wide
  • with the .babelrc you are using a file-relative configuration which only applies to the current package... and not to Bootstrap (Babel would use its .babelrc if it had one).

As noted on the following page a babel.config.js file should work better in your case: https://babeljs.io/docs/en/configuration#what-s-your-use-case

Ahhh, maybe that is the "problem" what causes that behaviour. I don't know about another .babelrc. Maybe we can complete the docs explaining that in order to help other users that have the same problem

@ger86
Copy link
Author

ger86 commented Apr 16, 2019

Hi @ger86,

Just a simple question, what's your need to transpile Bootstrap source code, when you can only include what you need of Bootstrap thanks to the files in js/dist.
The files in the js/dist are already transpiled separately

import 'bootstrap/js/dist/dropdown'

Yes, because when Bootstrap 4 was released the files in dist was not ES6 modules, so I can't use in that way..

@Johann-S
Copy link

@ger86 according to what you said, you should think about updating your Bootstrap version because we released several security fixes and you'll be able to use the dist files

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants