MFE header override

So we’ve been trying to do this, but running into issues. Wondering if there are any gotchas, version incompatibilities, etc.?

For reference, this is what we did:

  1. forked GitHub - edx/frontend-component-header

  2. created a new branch off v2.2.2 (the current version we were using), and made a minor tweak

  3. pushed it to a public gitlab repository

  4. installed in the mfe as:

npm install  '@edx/frontend-component-header@git+https://gitlab.com/path/to/frontend-component-header-test.git#v2.2.2'

But then, building the MFE fails to resolve @edx/frontend-component-header:

ERROR in ./src/index.scss (./node_modules/css-loader/dist/cjs.js??ref--5-1!./node_modules/postcss-loader/src??ref--5-2!./node_modules/resolve-url-loader!./node_modules/sass-loader/dist/cjs.js??ref--5-4!./src/index.scss)
Module build failed (from ./node_modules/sass-loader/dist/cjs.js):
SassError: Can't find stylesheet to import.
  ╷
8 │ @import '~@edx/frontend-component-header/dist/index';
  │         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ╵
  src/index.scss 8:9  root stylesheet
 @ ./src/index.scss 2:26-248 22:4-35:5 25:25-247
 @ ./src/index.jsx

ERROR in ./src/index.jsx
Module not found: Error: Can't resolve '@edx/frontend-component-header' in './src'

This resolving fails for any form of @edx/frontend-component-header from css and js.

Is there some extra configuration we need, or an updated peer dependency, or …? It looks like something in the build chain isn’t following the alias, but we can’t figure out where.

@djoy or @kmccormick Can you help with this issue? Since edX is using the edx-frontend-component-header-edx fork, we figured that following the docs would Just Work™, but it didn’t :frowning:

I think the issue here is that when you install the package from npm, it is the compiled version of the package, and has a ‘dist’ folder with the compiled assets. The git repo doesn’t have this folder so it won’t work the same way.

Here is one thing you can do:

  1. Clone the git repo to a directory
  2. Run npm install && npm run build in this directory
  3. Install this as an alias using npm install '@edx/frontend-component-header@/path/to/git/repo'

Running npm run build will create the dist directory in the folder and the override should now work :slight_smile:

Thanks @xitij2000.

The git repo doesn’t have this folder so it won’t work the same way.

I see two problems with the assumption of this restriction:

  1. the official docs mention installing from git, npm, and local directory, so this use case should be supported.
  2. what’s special about the build process such that npm can’t build it properly when installing from git source? This is the first package where I’ve experienced it failing to run when installed from git.

I tried installing from the local directory according to your instructions though, and get this:

Module not found: Error: Can't resolve 'react-responsive' in '/path/to/custom-header/dist'

I did previously try publishing to npm and that didn’t work (same errors as from git). However, just now I tried npm install && npm run build && npm publish, and the resulting package does work. So I guess that’s a kind of work-around for now.

But how can we do local development and testing on this? We don’t want to publish a new npm package every time we want to test changes locally, or run a test deployment. :confused:

I’m afraid the official docs might be wrong in this case. The mechanism they outline is correct, but the way these components are imported means that it won’t work without running he build step first.

When you install a package from the npm registry it downloads a pre-built package which contains only the compiled assets. You can see this here from the package for the header component: https://registry.npmjs.org/@edx/frontend-component-header/-/frontend-component-header-2.2.7.tgz

For local development here is what you can do:

  1. You can use local module overrides to override the location is looks for the header component: GitHub - edx/frontend-build
    OR
    You can use npm aliases to get the same effect. Clone the frontend app you want to work with and frontend-component-header in your projects folder. Go to the frontend app folder, and install your local copy of the header component by running npm install '@edx/frontend-component-header@~/projects/frontend-component-header'
  2. Run npm install in the frontend-component-header directory.
  3. Run npm run build in the frontend-component-header directory.
  4. Run npm start in the frontend app directory.

If you change the frontend component, you will need to run npm run build in that directory again. One way around this is to temporarily modify the SCSS and JavaScript imports so that the component is loaded from the src directory instead of dist.

Late to the conversation, but I think @xitij2000 is right. Without the build step, the dist directory won’t exist for most libraries and so it won’t be able to find the assets. If you’re pointing at a release tag on Github, it’s possible it works since Github has the built assets associated with the tag? I’m not sure exactly. It seems as if we should update that doc to be clearer and more correct.

Maybe it would be a good idea to add by default a “prepare” script in the package.json file with something like:

"prepare": "npm run build", 

The prepare script is run when the package is installed through git. https://docs.npmjs.com/cli/v7/using-npm/scripts#life-cycle-scripts

With that change, I think that the installation from github should work.

1 Like

Oh yes, that looks like it would be perfect! I knew there must be something like that, otherwise it wouldn’t be possible to install most packages from git or local filesystem. :+1:

That is a pretty convoluted method there; hopefully we can develop support for a more streamlined method. :confused: Maybe adding a “prepare” script as @morenol suggests could improve things? As @djoy points out, without a build step, most libraries aren’t going to work, so other libraries must have some solution to allow installing from source/git/filesystem. I’m not sure though, and don’t have any more spare time to experiment further right now unfortunately.

@swalladge Adding a prepare script might solve the issue when installing from git, but that will not solve the following problem:

With the prepare script in place the build step can run when you’re installing from git. However, if you make a change locally and want to test it, it won’t show up, since the package will be loaded from the dist directory, which will contain outdated builds. You will still need to run npm run build again after each change you want to test.

Which is why I recommend adding the local module override for development. The prepare script will be useful during deployment since it will make sure that the dist directory exists when the package is being installed on the server.

1 Like