387

I'm starting out a new vue.js project so I used the vue-cli tool to scaffold out a new webpack project (i.e. vue init webpack).

As I was walking through the generated files I noticed the following imports in the src/router/index.js file:

import Vue from 'vue'
import Router from 'vue-router'
import Hello from '@/components/Hello' // <- this one is what my qusestion is about

Vue.use(Router)

export default new Router({
    routes: [
        {
            path: '/',
            name: 'Hello',
            component: Hello
        }
    ]
})

I've not seen the at sign (@) in a path before. I suspect it allows for relative paths (maybe?) but I wanted to be sure I understand what it truly does.

I tried searching around online but wasn't able to find an explanation (prob because searching for "at sign" or using the literal character @ doesn't help as search criteria).

What does the @ do in this path (link to documentation would be fantastic) and is this an es6 thing? A webpack thing? A vue-loader thing?

UPDATE

Thanks Felix Kling for pointing me to another duplicate stackoverflow question/answer about this same question.

While the comment on the other stackoverflow post isn't the exact answer to this question (it wasn't a babel plugin in my case) it did point me in the correct direction to find what it was.

In in the scaffolding that vue-cli cranks out for you, part of the base webpack config sets up an alias for .vue files:

Alias location within project

This makes sense both in the fact that it gives you a relative path from the src file and it removes the requirement of the .vue at the end of the import path (which you normally need).

Thanks for the help!

Flip
  • 5,443
  • 6
  • 39
  • 69
Chris Schmitz
  • 18,484
  • 26
  • 78
  • 127
  • 4
    [See my comment](http://stackoverflow.com/questions/42711175/what-does-the-symbol-do-in-javascript-imports#comment72543541_42711175). – Felix Kling Mar 12 '17 at 16:47
  • 4
    @FelixKling It is not an exact duplicate because it doesn't answer the whole question, *is this an es6 thing? A webpack thing? A vue-loader thing?* – Estus Flask Mar 12 '17 at 16:52
  • 1
    Yeah, I think the question was similar but not a duplicate. Regardless I figured out where it was coming from and updated the question with an explanation since I can't add it as an answer. – Chris Schmitz Mar 12 '17 at 16:56
  • 1
    @estus: the answer makes it pretty clear that it isn't part of ES6 but a webpack configuration thing, don't you think? And that's exactly the case here as well, only that the nature of the configuration is a bit different. – Felix Kling Mar 12 '17 at 17:05
  • @FelixKling I believe when estus pointed out that there was still a question about what kind of a thing it is I had not yet added the update (I saw his comment come in as I was typing the update). I'm all set and there's a detailed explanation about my particular instance so I'm good to go. Thanks guys. – Chris Schmitz Mar 12 '17 at 17:08
  • I still believe this is a duplicate. If you want you could post your information over there as answer, or wait until this one is reopened. – Felix Kling Mar 12 '17 at 17:09
  • @FelixKling If the question is more narrow than a 'dupe' and has a chance to get more detailed answer, why should it be closed? It is obvious for me that it is Webpack thing, but the OP asked if it is specific to Vue loader or not. – Estus Flask Mar 12 '17 at 17:12
  • @estus: I understand your point. But isn't the whole point of having "more generic" questions/answeres for them to be applicable to more situations and therefore more questions could be closed as dupes of them? What's the point in repeating the same answer if only one sentence is different. What would you do if someone asks the question tomorrow: "What's the meaning of @ in an import in a FooBar project?" (where FooBar is another amazing library and webpack is used as module bundler)? – Felix Kling Mar 12 '17 at 17:28
  • 1
    @FelixKling It depends. But since the question you've linked doesn't have detailed answer that explains what's up with Webpack, it may probably deserve an answer. Usually having 'Possible duplicate of ...' comment is enough to designate the link between the questions, and vox populi does the rest. I've seen the questions being over-duped on SO too often. – Estus Flask Mar 12 '17 at 17:40
  • @ggorlen all good – Chris Schmitz Jan 10 '22 at 13:36

6 Answers6

333

This is done with Webpack resolve.alias configuration option and isn't specific to Vue.

In Vue Webpack template, Webpack is configured to replace @/ with src path:

  const path = require('path');

  ...
  resolve: {
    extensions: ['.js', '.vue', '.json'],
    alias: {
      ...
      '@': path.resolve('src'),
    }
  },
  ...

The alias is used as:

import '@/<path inside src folder>';
Estus Flask
  • 179,509
  • 61
  • 360
  • 499
  • 231
    JavaScript just isn't JavaScript anymore. Babel/webpack gives us this Frankenstein language and somehow new developers are meant to know where ECMAScript spec ends and userland plugins/transforms begin. It's really sad, imo. – Mulan Mar 13 '17 at 04:13
  • 3
    @naomik It's up to user to introduce such tricks into the setup or not. It's not a big deal for Vue since it relies on its custom .vue file format anyway. – Estus Flask Mar 13 '17 at 10:58
  • 22
    Personally I think the ability to add flexibility if you want it is a good thing. I see it less as frankenstein and more like voltron; you can do stuff as a lion or combine different lions together to have a bigger robot. Yeah, sometimes you get questions like this one, but it's not like the answers can't be found. Really, you can take the frankenstein or voltron view with any project of any size, it's just "using and understanding dependencies". – Chris Schmitz Mar 13 '17 at 14:39
  • 1
    @ChrisSchmitz It depends on the context and the perspective. Doing something like this will restrict the project to use Webpack. May be not a good thing if the project intends to use native ES6 modules when they will arrive, or it's Node where CommonJS can be used for modules. Long relative paths can be harder to maintain and refactor, on the other hand. – Estus Flask Mar 13 '17 at 14:49
  • Jeeze, this was happening a year ago. I'm just getting started and I'm wondering how far gone everything is. :P – Luddens Desir Dec 05 '18 at 00:44
  • Does this work for import assets? mean import a css file in the style section on a SFC vue file. – Kevin Jan 03 '19 at 05:32
  • @Kevin This depends on your setup. Yes, this may work for css as well. As it can be seen in the snippet, `extensions` option specifies extensions that are affected. – Estus Flask Jan 03 '19 at 10:38
  • Set an alias for asset folder works for me, e.g: 'assets': resolve('src/assets'), so I can import like this: @import "~assets/css/iconfont.css"; – Kevin Jan 03 '19 at 10:55
  • 8
    When using `vue-cli` v3+ you should use `~@` to reference `src` folder. E.g.: `$font-path: '~@/assets/fonts/';` – Consta Gorgan Jan 25 '19 at 23:18
  • @AnthonyWinzlet The link seems to be wrong, it refers to this post. – Estus Flask Apr 05 '19 at 07:14
  • @estus oops. Apologies here it is https://stackoverflow.com/questions/55509973/how-to-define-socket-variable-globally – Ashh Apr 05 '19 at 07:15
  • @AnthonyWinzlet This question is unrelated, though I was able to answer it, so I've tried to do this. – Estus Flask Apr 05 '19 at 07:32
  • @estus I cannot find this file in my project. Is a global configuration? Where can I find (and change it)? – Ahmad Shahwan May 14 '19 at 20:00
  • @AhmadShahwan Webpack configuration is stored by default in webpack.config.js, but this may differ depending on a project. – Estus Flask May 14 '19 at 23:08
  • Thank you @estus. After searching, I think that the webpack.config.js used is the one shipped in vue-cli package, and is loaded by its service. – Ahmad Shahwan May 15 '19 at 12:50
  • 1
    @AhmadShahwan If you're using vue-cli then that's true. You can access webpack.config.js directly by ejecting the project but you likely don't need to do that, see https://cli.vuejs.org/guide/webpack.html – Estus Flask May 15 '19 at 12:58
  • does this also apply to the *.js files in a new vue project or only .vue files? – Tallboy Sep 06 '20 at 16:43
  • @Tallboy Yes, to all script files. You can see this here, https://github.com/vuejs-templates/webpack/blob/1.3.1/template/build/webpack.base.conf.js#L35-L41 – Estus Flask Sep 06 '20 at 16:49
  • Question, why we need to use ```@``` when we can use ```src``` directly? What's the advantages of this extra layer of functionality? – Rinto George Oct 20 '20 at 10:12
  • 1
    @RintoGeorge To avoid relative paths in imports, it's `@/lib/foo` instead of `../../../lib/foo`. `@` is the shortest name and doesn't collide with NPM packages. Doing the same thing for `src/lib/foo` absolute path is an extra layer too because it's not standardized and depends on a setup similarly to `@` (also there's certainly a package of the same name). – Estus Flask Oct 20 '20 at 10:28
26

Also keep in mind you can create variables in tsconfig as well:

"paths": {
  "@components": ["src/components"],
  "@scss": ["src/styles/scss"],
  "@img": ["src/assests/images"],
  "@": ["src"],
}

This can be utilized for naming convention purposes:

import { componentHeader } from '@components/header';
Tyler Canton
  • 471
  • 6
  • 14
  • But this kind of alias will be left bare in the source JS and then at run-time you'll need to have a wrapper intercede to make the alias work. Maybe there's a way via babel for this TS syntax to get converted at build time? With Typescript's `tsc` is does not and therefore you'll need something like `module-alias` or `tsconfig-paths`. – ken May 27 '20 at 22:55
  • 1
    after I add this settings, vs code can not reslove path and cannot go into the file when click the impored module. – JackChouMine Oct 16 '21 at 07:19
5

I get over with following combination

import HelloWorld from '@/components/HelloWorld'
=>
import HelloWorld from 'src/components/HelloWorld'

IDE will stop warning the uri, but this causes invalid uri when compile, in "build\webpack.base.conf.js"

resolve: {
  extensions: ['.js', '.vue', '.json'],
  alias: {
    'src': resolve('src'),
  }
},

Bingoo!

2

resolve('src') no works for me but path.resolve('src') works

resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js',
      '@': path.resolve('src')
    },
    extensions: ['*', '.js', '.vue', '.json']
  },
2

Maybe try adding in webpack. mix.webpackConfig references laravel mix.

mix.webpackConfig({

    resolve: {
        alias: {
            '@imgSrc': path.resolve('resources/assets/img')
        }
    }
});

And then in vue use.

<img src="@imgSrc/logo.png" />
Paul
  • 99
  • 5
1

Something must have changed. The answer given here is no longer correct. This project in Chapter09 uses the @ sign in its import statements but the webpack.config.js file doesn't have a path resolve statement:

let service = process.VUE_CLI_SERVICE

if (!service || process.env.VUE_CLI_API_MODE) {
  const Service = require('./lib/Service')
  service = new Service(process.env.VUE_CLI_CONTEXT || process.cwd())
  service.init(process.env.VUE_CLI_MODE || process.env.NODE_ENV)
}

module.exports = service.resolveWebpackConfig()
Dean Schulze
  • 8,815
  • 19
  • 85
  • 143