Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Resolving JavaScript modules via 'gf' in Vim when using a Webpack tilde alias

I'm a new member of a Vue.js project that uses the tilde (~) notation in module imports, as in

import WhateverApi from '~/api/whatever';

The project repository contains all kinds of files all thrown together: a Vagrant machine, a Laravel backend application, config files and a Vue.js SPA. The latter is in a nested folder structure (resources/assets/js/), which should be interpreted as the project root, hence ~.

Using Vim, I'm used to being able to jump to a linked file via gf. When I do that on the path shown above, Vim complains that the file does not exist, as it probably interprets the tilde (somewhat correctly) as the user's home folder.

Googling yielded no result, mainly because I'm at a loss what exactly to search for. This appears to be some magic Webpack is doing. As the other team members use WebStorm/PHPStorm, they do not have this problem.

How do I get Vim to resolve the path correctly within the project scope?

Update with an example:

Webpack has an alias setting, which allows to define any path as an alias to use in source code files. It looks like this:

resolve: {
    alias: {
        vue$: 'vue/dist/vue.esm.js',
        '~': path.resolve(__dirname, 'resources/assets/js'),
        sass: path.resolve(__dirname, 'resources/assets/sass'),
    },
    extensions: ['*', '.js', '.vue', '.json'],
},

Ignore the $vue key, it's specific to Vue.js with Webpack. ~ and sass are interesting. The first one is basically a substitute filter that exchanges every ~ in paths to resources/assets/js. The same for sass with it's according path. However, the import statements vary. Here's an example of a Vue single file component with both import statements as an example:

<template>
    <div>
        <p>Some content.</p>
    </div>
</template>

<script>
    import WhateverApi from '~/api/whatever';

    export default {};
</script>

<style lang="scss" scoped>
    @import '~sass/variables/all';
</style>

Now, when using gf, it would be fantastic if it could resolve those (weird) combinations according to the following rules:

  • Paths starting with ~/ should replace ~ to resources/assets/js and try to find files by attaching the extensions .js, .vue and .json.
  • Paths starting with ~sass should replace ~ to resources/assets/sass and try to find files by attaching the extension .scss.

I know this is involved — and happened way before I joined the team. There's an interesting project trying to simplify this (https://github.com/davidosomething/vim-enhanced-resolver) but unfortunately it appears to be broken, as it throws errors trying to resolve an existing path.

Any help is greatly appreciated.

like image 209
herrbischoff Avatar asked Jul 10 '18 19:07

herrbischoff


3 Answers

Googling yielded no result, mainly because I'm at a loss what exactly to search for.

For Vim help, try first Vim help itself. For example, which command are you using? If it is gf, check the help of gf to see how it works:

:h gf
[count]gf       Edit the file whose name is under or after the cursor.
                Mnemonic: "goto file".
                Uses the 'isfname' option to find out which characters
                are supposed to be in a file name.  Trailing
                punctuation characters ".,:;!" are ignored. Escaped
                spaces "\ " are reduced to a single space.
                Uses the 'path' option as a list of directory names to
                look for the file.  See the 'path' option for details
                about relative directories and wildcards.
                Uses the 'suffixesadd' option to check for file names
                with a suffix added.
                If the file can't be found, 'includeexpr' is used to
                modify the name and another attempt is done.

You can also check :h 'includeexpr'. For example, this will expand an initial ~ to resources/assets/js:

set inex=substitute(v:fname,'^\\~','resources/assets/js','')
like image 158
sidyll Avatar answered Oct 16 '22 22:10

sidyll


After sidyll pointed me in the right direction, I managed to get this to work after quite some tinkering and reading help pages. The secret is a combination of recursive substitute() calls, regex capture groups and suffixesadd:

set includeexpr=substitute(substitute(v:fname,'^\\~\/','resources/assets/js/',''),'^\\~sass/\\(.*\\)/\\(.*\\)$','resources/assets/sass/\\1/_\\2','')
set suffixesadd=.js,.vue,.scss

This is rather ugly but that's Vimscript for you.

like image 4
herrbischoff Avatar answered Oct 17 '22 00:10

herrbischoff


The method with substitude and includeexpr involves storing a project path in the vim configuration. it's far from ideal.

With the plugin vim-npr, I managed to do that perfectly.

like image 1
Pierre Maoui Avatar answered Oct 16 '22 23:10

Pierre Maoui