Webpacker: Allow me to specify exactly which paths to load

Created on 30 Nov 2018  路  15Comments  路  Source: rails/webpacker

Our webpacker config appears to be loading all of our test files and helpers for production builds. I need to exclude any files that end with .spec.ts now because since upgrading to rails 5.2.1 dev dependencies are no longer installed, which breaks the build since the spec files are looking for dev dependencies which aren't there. I _do_ need to include any that end with just .ts, though (which are in the same directories as the ones with spec.ts, per angular community guidelines).

I see that webpacker automatically globs directories passed to resolved_paths, so I can't specify my own path there (i.e. the path I really want is app/assets/angular/**/*[^spec].ts, not just app/assets/angular/**/*). I also tried adding [^spec].ts to the extensions list, hoping webpacker would generate a path like app/assets/angular/**/*[^spec].ts, but it does not.

How do I tell webpacker to load only .ts files in app/assets/angular that do _not_ end with spec.ts?

Most helpful comment

I ran in to a similar situation - it's very common convention in the react community (and as I'm learning the JS community as a whole) to put test & other files next to the code rather than in a separate testing folder structure like in rails.

in my case I have:

/app/javascript/packs/
    application.js
/app/javascript/react/component/
    Component.jsx
    Component.test.js
    Component.stories.js

a simple add to config/webpack/production.js

environment.loaders.get('babel').exclude = [/\.test\.js$/, /\.stories\.js$/, environment.loaders.get('babel').exclude]

Has me back and working.

It would be slick to see this exposed in webpacker.yml as a configuration option as I'm sure all the different frameworks will need slightly different files excluded and doing it automatically as part of initial setup will save a lot of people that getting started headache.

All 15 comments

Do you link to any tests via entry points? Normally you would have a seperate webpack config that links to all the spec.ts files (or a central file that links to all spec.ts files). I remember back from my Angular days that it was especially finicky with tests.

As a stop-gap solution, consider moving your devDependencies to dependencies with minimal consequences (a longer yarn install). There's an active discussion on this over here: https://github.com/rails/webpacker/issues/1212#issuecomment-442228316

Thanks for the quick reply! I'm not 100% sure what you mean by "link to tests via entry points". We have two entry points for production builds, application.js and polyfills.js. I've run dependency graphs on both of those files and neither include any test dependencies.

As far as I understand how webpacker works, the separate webpack configs (including a separate one for dev/test that link to all the spec.ts files) are generated by the config in webpacker.yml, is that true?

So I guess my question is how do I tell webpacker in webpacker.yml exactly which files I want it to include for that environment?

I see how moving all of our dev dependencies to dependencies would solve this, but it seems like there should be a way to tell webpacker how to generate an environment-specific webpack config that only includes certain files. The only documentation I can find is this, which doesn't go into detail about how to use resolved_paths or extensions to build the kind of webpack config I'm after.

I need a development config that includes all .ts files, and a production config that _excludes_ only .spec.ts files and files in specs/javascript. Greatly appreciate any insight you might have.

So I guess my question is how do I tell webpacker in webpacker.yml exactly which files I want it to include for that environment?

I must admit, I know more about Webpack than WebpackER. That being said, it sounds like WebpackER is eagerly loading your *.spec.ts files or you need a exclude: /\.spec\.ts$/ on one of your loaders (last one below). The only mechanism I could find that indicates eager loading is:

"Packs" is a special directory made only for webpack entry files so don't put anything here that you don't want to link in your views.

ts-loader/tsconfig could also have a missing exclude:
https://github.com/rails/webpacker/blob/eae46c52220a03033168c06bc9064025781f0640/lib/install/examples/typescript/tsconfig.json#L17

You could also be missing a needed exclude (exclude can be added for most loaders)
https://github.com/rails/webpacker/blob/e70deb358e29004274cc1e6581ab19abd62e00b0/docs/testing.md#L44

Unfortunately that's all I got, hope it helps.

Thanks for the tips.. I've tried excluding specs in our tsconfig.json and in the typescript loader, but maybe there's something more to look into related to other loaders or somehow getting that config into a webpack config via webpacker.yml. I appreciate you answering questions like this was stack overflow! I'll close this since I haven't found a solution and don't plan on pursuing anything like a PR about it.

In case anyone else runs into the same issue,the workaround described here worked https://github.com/rails/webpacker/issues/440 (stopping webpacker from "enchancing" normal asset precompilation rake tasks), but we ended up just moving all of our dev dependencies to dependencies.

I think I've run into a similar issue. We have a component folder structure like below:

  • cool-component (folder)

    • cool-component.jsx

    • cool-component.test.js

    • cool-component.md

I found that the Webpacker creates an entry property on the final webpack config with all my components, but instead of targeting the actual component, sometimes it selects the test file.

I've traced my problem to this area in the environments/base file. In some cases, the getEntryObject method targets my test file instead of the actual component entry file. Since my test file imports my component, production works fine; the bundles have what we need. Unfortunately, they also have unnecessary test code, too.

This is an example of what I get when I log the contents of entry:

{
  ... ,
  'components/cool-component/cool-component': '/some/root/folder/packs/components/cool-component/cool-component.test.js',
  ...
}

My guess is that it matched the jsx file then matched the test.js file and overwrote the correct path (the .jsx file).

I'm not sure how to solve this. One thought was adding an ignore pattern in the yml that getEntryObject could reference, i.e. \(/.test./)\. Another thought was to recreate getEntryObject in the webpack/environment.js file and properly build that entry object there but that might make upgrading difficult

I tried adding exclude conditions to the rules but that had no affect. I'm not that great with webpack and in debugging why the exclude didn't work, it lead me to the above findings.

My last option is to not use the yml at all and just create the webpack config myself. :(

Anyone else have thoughts on this?

I'm not sure how to solve this.

Just don't put your components under packs, you can place it in src or create a components folder that is directly under javascripts:

image

Oh. I totally misunderstood the intention of "packs". Derp. Thanks! :D

I ran in to a similar situation - it's very common convention in the react community (and as I'm learning the JS community as a whole) to put test & other files next to the code rather than in a separate testing folder structure like in rails.

in my case I have:

/app/javascript/packs/
    application.js
/app/javascript/react/component/
    Component.jsx
    Component.test.js
    Component.stories.js

a simple add to config/webpack/production.js

environment.loaders.get('babel').exclude = [/\.test\.js$/, /\.stories\.js$/, environment.loaders.get('babel').exclude]

Has me back and working.

It would be slick to see this exposed in webpacker.yml as a configuration option as I'm sure all the different frameworks will need slightly different files excluded and doing it automatically as part of initial setup will save a lot of people that getting started headache.

@JeremiahChurch I have the same file structure as you listed above and I was hoping your solution would work but I'm stilling seeing my react test files in the webpack analysis of the production build...any ideas?

@JeremiahChurch I have the same file structure as you listed above and I was hoping your solution would work but I'm stilling seeing my react test files in the webpack analysis of the production build...any ideas?

I ended up having to use this nasty regex in my application.js pack

const componentRequireContext = require.context(
  "components",
  true,
  /^(?!.*(test.js$)).*\.(?:jsx|js)$/
);

@JeremiahChurch I have the same file structure as you listed above and I was hoping your solution would work but I'm stilling seeing my react test files in the webpack analysis of the production build...any ideas?

@wileybaba Sorry that isn't working for you - I just checked that applications production config - that line is unchanged and still working.

I also just tested it in a much simpler default production.js file - as seen below - it looks to be working as expected as well.

process.env.NODE_ENV = process.env.NODE_ENV || 'production'

const environment = require('./environment')

environment.loaders.get('babel').exclude = [/\.test\.js$/, /\.stories\.js$/, environment.loaders.get('babel').exclude];

module.exports = environment.toWebpackConfig()

Adding in this comment to help benefit those working on projects that follow a standard of placing all frontend test code into nested __tests__/ directories. I used an adaptation of @wileybaba's solution, but just with an adjusted regex. This allows entire directories to be excluded, as opposed to just the test files themselves (I'm trying to consider files that aren't running tests directly, such as mock setup or test utility function files).

const componentRequireContext = require.context("components", true, /^(?!.*__tests__\/.*$).+\.[jt]sx?$/)

@ecbrodie I wonder if using something like https://github.com/cherrry/ignore-loader would help.

@akshaysmurthy +1. None of the other solutions worked for me. But adding the following to my config/webpack/production.js did the trick:

const ignoreTestFiles = {
  test: /test\.js$/,
  use: 'ignore-loader'
}

environment.loaders.append('ignoreTestFiles', ignoreTestFiles)

@akshaysmurthy that loader seems to be abandoned and only supports old webpack versions.

My solution has been in place on my webpacker project for months now without issue.

Was this page helpful?
0 / 5 - 0 ratings