I was experiencing really slow "boot" times for Karma test runner and after profiling the run, I realised that the largest slow down was caused by the creation of source maps.
More specifically, given that I'm using karma-webpack
and webpack as a pre-processor, every time a test file is loaded by karma, it is fed to webpack which generates a source map for it.
Given that I wasn't splitting/chunking my app and vendor code, each test file was getting the same vendor source map (inlined).
I thought that I could fix this by simply preventing source mapping from occurring for node_modules/
files, but realised that you can only exclude files from getting source mapped, based on final asset files, not on input source/module files.
So I found this plugin to automatically split my app and vendor code into separate chunks (as opposed to having to manually list each vendor module).
Yet I started to get this error when running Karma:
ReferenceError: Can't find variable: webpackJsonp
I'm pretty sure this is caused by the fact that Karma is not picking up on the fact that the vendor and app code are being split into separate chunks and hence is only including code configured with the files
option (i.e. the test files themselves and not the vendor file).
It seems as if that files
config option is parsed and handled before each test file is pre-processed, meaning I don't think it's possible to specify the vendor chunk in the files
option, because Karma won't know about it at the time it tries to look for it (too early).
The only solutions I can see are:
- Change the way Karma is implemented, such that it can handle the separation of vendor and app chunk files.
- Instead of using
karma-webpack
and pre-processing, build the app in a test mode and then run Karma of the test build directory (so that the vendor chunk will exist early enough).
Is there a solution that I have missed?
I find it strange that it doesn't seem to be a common problem.
Edit 1
I found this, but the people there are suggesting the use of multiple entry points in the webpack config (i.e. one for the app and one for vendor). I will try and see if this works with Karma, but it still has a big downside (in my opinion) that you have to manually keep track of what you put in the vendor
array. I.e. every time you install a package you have to add it to the array and vice versa.
Edit 2
Using multiple entry points (in the webpack config) doesn't even work before I configure the source map webpack plugin to exclude vendor files (whereas it would with the webpack-split-by-path
plugin).
I'm going to try and implement the "build first and then test" approach.
If anyone else comes across this problem, I got the "build then rest" approach working, i.e. I abandoned
karma-webpack
and Karma pre-processing, in favour of separate build and test commands (which get run one after the other).Here is my webpack config that is specific to testing (e.g. webpack.config.babel.test.js):
The key part is that it creates an entry point for each test file and uses the
webpack-split-by-path
plugin to automatically separate app from vendor code, when generating chunks.Here is the karma config I went with:
The key part is that the vendor file is listed first in the
files
config option and is set to not be watched, followed by the test files. This ensures that the vendor code is always loaded/inserted first for each test case.My question asks if there is another way, but this approach works quite well. The performance is much better.
Edit 1
The only drawback of this approach (which I didn't realise at first) is that you can't really achieve test watching, as you could with
karma-webpack
and the pre-processing (by webpack), because of the decoupling of the build and test steps.Edit 2
This approach suffered from the problem of re-transpiling vendor code every time you change your application code (even if you didn't add/remove any vendor libraries). This slowed things down redundantly.
What you want to do to solve this problem and also to be able to start test watching again is this:
dist-test/
dir whenever your application code changes.dist-test/
dir.This solution is perfect, except for the one drawback that you can't run both of those things in one npm/yarn command.
Note: That your output file names for your Webpack test build shouldn't contain any hashes (i.e. the file names should remain consistent between changes of their content). This is so that when you change a test file, you don't run the old and the new test code (because of Webpack not deleting the old file)..