What does the @ mean inside an import path?
Asked Answered
L

13

435

I'm starting 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 question 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 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!

Lactation answered 12/3, 2017 at 16:31 Comment(9)
See my comment.Fractious
@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?Oocyte
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.Lactation
@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.Fractious
@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.Lactation
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.Fractious
@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.Oocyte
@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)?Fractious
@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.Oocyte
O
379

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>';
Oocyte answered 12/3, 2017 at 20:54 Comment(22)
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.Knew
@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.Oocyte
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".Lactation
@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.Oocyte
Jeeze, this was happening a year ago. I'm just getting started and I'm wondering how far gone everything is. :POffshore
Does this work for import assets? mean import a css file in the style section on a SFC vue file.Utricle
@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.Oocyte
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";Utricle
When using vue-cli v3+ you should use ~@ to reference src folder. E.g.: $font-path: '~@/assets/fonts/';Haire
@AnthonyWinzlet The link seems to be wrong, it refers to this post.Oocyte
@estus oops. Apologies here it is #55510473Shelia
@AnthonyWinzlet This question is unrelated, though I was able to answer it, so I've tried to do this.Oocyte
@estus I cannot find this file in my project. Is a global configuration? Where can I find (and change it)?Amain
@AhmadShahwan Webpack configuration is stored by default in webpack.config.js, but this may differ depending on a project.Oocyte
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.Amain
@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 cli.vuejs.org/guide/webpack.htmlOocyte
does this also apply to the *.js files in a new vue project or only .vue files?Comedic
@Comedic Yes, to all script files. You can see this here, github.com/vuejs-templates/webpack/blob/1.3.1/template/build/…Oocyte
Question, why we need to use @ when we can use src directly? What's the advantages of this extra layer of functionality?Lepage
@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).Oocyte
Can I usually replace @/ with ./ ? Is there any difference ?Umbilicus
@AlexanderFilippovich The difference is that ./ is relative path, and aliased one is absolute. You use an alias if you don't want ../../../... paths and don't want to refactor them when module location is changedOocyte
L
38

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';
Linseed answered 19/4, 2019 at 15:39 Comment(3)
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.Stamford
after I add this settings, vs code can not reslove path and cannot go into the file when click the impored module.Trod
In what file do I usually need to define the "paths" Object ?Umbilicus
G
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!

Gripping answered 12/6, 2019 at 14:41 Comment(0)
A
3

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" />
Alkaline answered 22/5, 2020 at 17:43 Comment(0)
C
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']
  },
Clyte answered 17/9, 2019 at 22:16 Comment(0)
C
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()
Conveyance answered 16/7, 2020 at 17:29 Comment(0)
J
1

A similar approach used in Vue3 and Vite, the alias can be found in vite.config.js

// https://vitejs.dev/config/
export default defineConfig({
  plugins: [vue(),vueJsx()],
  resolve: {
    alias: {
      "@": fileURLToPath(new URL("./src", import.meta.url)),
    },
  },
});
Junta answered 30/8, 2022 at 23:48 Comment(0)
C
1

In simple words, the "@" symbol is used as "src" when importing files/components.

I have configured my webpack.common.js file like below

resolve: {
  extensions: [".ts", ".js", ".vue"],
  alias: {
      '@': path.resolve(__dirname,'src/')
  }
}

I have imported the vuex store like this import store from "@/store"; instead of import store from "../store"

You can read more about Webpack Aliases in Vue here

Cichlid answered 14/6, 2023 at 9:7 Comment(0)
C
0

An example to apply in Next.js would be to use the file next.config.js to add the next content.

const path = require('path');

module.exports = {
  webpack: (config, options) => {
    config.resolve.alias = {
      '@': path.resolve(process.cwd(), 'src'),
    };
    return config;
  }
};
Conformal answered 14/6, 2022 at 7:36 Comment(0)
C
0

It refers to an alias path found in your config.js file

Cacique answered 8/12, 2022 at 19:22 Comment(1)
Hey @jocoio, thanks for hopping in and adding an answer. It's always awesome to see new contributors looking to help! A bit of help from my end: your answer is correct, but to be more helpful for people who come across it you could provide more explanation and context. Check out the other answers to the question here. there are lots of great examples to go by. Thanks again for chipping in 🙌🏽Lactation
V
0

@ refers to the src folder inside your root directory, it can be configured while bootstrapping your app.

Vivisectionist answered 12/1, 2023 at 12:14 Comment(0)
K
0

We sometimes use '@' to import from a components directory with a path "src/components/Add.vue". If we need to access this file from a diff directory like "src/views/AboutView.vue", we can use this to import Add.vue inside AboutView.vue as import Add from "@/components/Add.vue", inside your tag. This is the same as using import Add from "../components/Add.vue" '@' points to the root directory of your app(src folder)

Kagoshima answered 3/4, 2023 at 6:8 Comment(1)
I t should read, '@' refers to the 'src' folder in your root dir.Kagoshima
H
-3

import { createApp, markRaw } from "vue";

import { createPinia } from "pinia";

import App from "./App.vue";

import router from "./router";

// import "./assets/main.css";

const app = createApp(App);

const pinia = createPinia()

pinia.use(({ store })=>{ store.$router = markRaw(router) })

app.use(pinia);

app.use(router);

app.mount("#app");

Heald answered 6/2, 2023 at 2:9 Comment(1)
As it’s currently written, your answer is unclear. Please edit to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center.Boulware

© 2022 - 2024 — McMap. All rights reserved.