5

I want to be able to use absolute paths in @import statements. Something like:

@import '/templates/common/variables'

However, sass seems to resolve it as an absolute url within my filesystem. I want it to look in my project folder. Eg. my file is actually located at /home/username/project/templates/common/_variables.scss

Is that somehow possible?

I already looked at includePaths but that seems to do nothing at all.

I'm using encore to write my webpack file, it looks roughly like this:

const Encore = require('@symfony/webpack-encore');
Encore
    .setOutputPath("web/build/")
    .setPublicPath("/build")
    // [...]
    .enableSassLoader(options => {
        options.includePaths = [path.resolve(__dirname, '/web')];
    })
;

And also here is the generated webpack configuration (quiet lengthy and i haven't replaced my real paths with my example paths from above):

{  
    context:'/var/www',
    entry:{  
        index:[  
            './polyfills.js',
            './web/typo3conf/ext/hn_project/ext_index.js',
            './web/typo3conf/ext/hn_templates/ext_index.js'
        ],
        backend:[  
            './polyfills.js',
            './web/typo3conf/ext/hn_project/ext_backend.js'
        ]
    },
    output:{  
        path:'/var/www/web/build',
        filename:'[name].[chunkhash:8].js',
        publicPath:'/build/',
        pathinfo:false
    },
    module:{  
        rules:[  
            {  
                test:/\.jsx?$/,
                exclude:/(node_modules|bower_components)/,
                use:[  
                    {  
                        loader:'babel-loader',
                        options:{  
                            cacheDirectory:true,
                            presets:[  
                                [  
                                    'env',
                                    {  
                                        modules:false,
                                        targets:{  
                                            browsers:[  
                                                'and_chr 67',
                                                'and_uc 11.8',
                                                'chrome 67',
                                                'chrome 66',
                                                'chrome 65',
                                                'edge 17',
                                                'edge 16',
                                                'firefox 60',
                                                'firefox 59',
                                                'firefox 52',
                                                'ie 11',
                                                'ie 10',
                                                'ie_mob 11',
                                                'ie_mob 10',
                                                'ios_saf 11.3',
                                                'ios_saf 11.0-11.2',
                                                'opera 53',
                                                'opera 52',
                                                'safari 11.1',
                                                'safari 11',
                                                'samsung 6.2'
                                            ],
                                            uglify:true
                                        },
                                        useBuiltIns:true
                                    }
                                ]
                            ],
                            plugins:[  

                            ]
                        }
                    }
                ]
            },
            {  
                test:/\.css$/,
                use:[  
                    {  
                        loader:'/var/www/node_modules/extract-text-webpack-plugin/dist/loader.js',
                        options:{  
                            omit:1,
                            remove:true
                        }
                    },
                    {  
                        loader:'style-loader'
                    },
                    {  
                        loader:'css-loader',
                        options:{  
                            minimize:true,
                            sourceMap:false,
                            importLoaders:1
                        }
                    },
                    {  
                        loader:'postcss-loader',
                        options:{  
                            sourceMap:false,
                            ident:'postcss',
                            plugins:[  
                                {  
                                    [  
                                        Function:plugin
                                    ]                                    options:{  
                                        grid:false
                                    },
                                    browsers:undefined,
                                    info:[  
                                        Function
                                    ],
                                    postcssPlugin:'autoprefixer',
                                    postcssVersion:'6.0.23'
                                }
                            ]
                        }
                    }
                ]
            },
            {  
                test:/\.(png|jpg|jpeg|gif|ico|svg|webp)$/,
                loader:'url-loader',
                options:{  
                    name:'images/[name].[hash:8].[ext]',
                    publicPath:'/build/',
                    limit:4096
                }
            },
            {  
                test:/\.(woff|woff2|ttf|eot|otf)$/,
                loader:'url-loader',
                options:{  
                    name:'fonts/[name].[hash:8].[ext]',
                    publicPath:'/build/',
                    limit:4096
                }
            },
            {  
                test:/\.s[ac]ss$/,
                use:[  
                    {  
                        loader:'/var/www/node_modules/extract-text-webpack-plugin/dist/loader.js',
                        options:{  
                            omit:1,
                            remove:true
                        }
                    },
                    {  
                        loader:'style-loader'
                    },
                    {  
                        loader:'css-loader',
                        options:{  
                            minimize:true,
                            sourceMap:false,
                            importLoaders:1
                        }
                    },
                    {  
                        loader:'postcss-loader',
                        options:{  
                            sourceMap:false,
                            ident:'postcss',
                            plugins:[  
                                {  
                                    [  
                                        Function:plugin
                                    ]                                    options:{  
                                        grid:false
                                    },
                                    browsers:undefined,
                                    info:[  
                                        Function
                                    ],
                                    postcssPlugin:'autoprefixer',
                                    postcssVersion:'6.0.23'
                                }
                            ]
                        }
                    },
                    {  
                        loader:'resolve-url-loader',
                        options:{  
                            sourceMap:false
                        }
                    },
                    {  
                        loader:'sass-loader',
                        options:{  
                            sourceMap:true,
                            includePaths:[  
                                '/web'
                            ]
                        }
                    }
                ]
            }
        ]
    },
    plugins:[  
        ExtractTextPlugin        {  
            filename:'[name].[contenthash:8].css',
            id:1,
            options:{  
                allChunks:false
            }
        },
        DeleteUnusedEntriesJSPlugin        {  
            entriesToDelete:[  

            ]
        },
        ManifestPlugin        {  
            opts:{  
                publicPath:null,
                basePath:'build/',
                fileName:'manifest.json',
                transformExtensions:/^(gz|map)$/i,
                writeToFileEmit:true,
                seed:null,
                filter:null,
                map:null,
                generate:null,
                sort:null,
                serialize:[  
                    Function:serialize
                ]
            }
        },
        LoaderOptionsPlugin        {  
            options:{  
                debug:false,
                options:{  
                    context:'/var/www',
                    output:{  
                        path:'/var/www/web/build'
                    }
                },
                test:{  
                    test:[  
                        Function:test
                    ]
                }
            }
        },
        HashedModuleIdsPlugin        {  
            options:{  
                hashFunction:'md5',
                hashDigest:'base64',
                hashDigestLength:4
            }
        },
        WebpackChunkHash        {  
            algorithm:'md5',
            digest:'hex',
            additionalHashContent:[  
                Function
            ]
        },
        ProvidePlugin        {  
            definitions:{  
                '$':'jquery',
                jQuery:'jquery',
                'window.jQuery':'jquery'
            }
        },
        CleanWebpackPlugin        {  
            paths:[  
                '**/*'
            ],
            options:{  
                root:'/var/www/web/build',
                verbose:false,
                allowExternal:false,
                dry:false
            }
        },
        DefinePlugin        {  
            definitions:{  
                'process.env':{  
                    NODE_ENV:'"production"'
                }
            }
        },
        UglifyJsPlugin        {  
            options:{  
                sourceMap:false
            }
        },
        FriendlyErrorsWebpackPlugin        {  
            compilationSuccessInfo:{  
                messages:[  

                ]
            },
            onErrors:undefined,
            shouldClearConsole:false,
            formatters:[  
                [  
                    Function:format
                ],
                [  
                    Function:format
                ],
                [  
                    Function:format
                ],
                [  
                    Function:format
                ],
                [  
                    Function:format
                ],
                [  
                    Function:format
                ]
            ],
            transformers:[  
                [  
                    Function:transform
                ],
                [  
                    Function:transform
                ],
                [  
                    Function:transform
                ],
                [  
                    Function:transform
                ],
                [  
                    Function:transform
                ],
                [  
                    Function:transform
                ]
            ]
        },
        AssetOutputDisplayPlugin        {  
            outputPath:'web/build',
            friendlyErrorsPlugin:FriendlyErrorsWebpackPlugin            {  
                compilationSuccessInfo:{  
                    messages:[  

                    ]
                },
                onErrors:undefined,
                shouldClearConsole:false,
                formatters:[  
                    [  
                        Function:format
                    ],
                    [  
                        Function:format
                    ],
                    [  
                        Function:format
                    ],
                    [  
                        Function:format
                    ],
                    [  
                        Function:format
                    ],
                    [  
                        Function:format
                    ]
                ],
                transformers:[  
                    [  
                        Function:transform
                    ],
                    [  
                        Function:transform
                    ],
                    [  
                        Function:transform
                    ],
                    [  
                        Function:transform
                    ],
                    [  
                        Function:transform
                    ],
                    [  
                        Function:transform
                    ]
                ]
            }
        },
        {  
            apply:[  
                Function:bound apply
            ]
        },
        ZopfliPlugin        {  
            asset:'[path].gz[query]',
            algorithm:[  
                Function
            ],
            filename:false,
            compressionOptions:{  
                verbose:false,
                verbose_more:false,
                numiterations:15,
                blocksplitting:true,
                blocksplittinglast:false,
                blocksplittingmax:15
            },
            test:/\.(js|css|svg|ttf)$/,
            threshold:1400,
            minRatio:0.8,
            deleteOriginalAssets:false
        },
        BrotliPlugin        {  
            asset:'[path].br[query]',
            test:/\.(js|css|svg|ttf)$/,
            threshold:1400,
            minRatio:0.8,
            deleteOriginalAssets:false,
            compress:[  
                Function
            ]
        }
    ],
    performance:{  
        hints:false
    },
    stats:{  
        hash:false,
        version:false,
        timings:false,
        assets:false,
        chunks:false,
        maxModules:0,
        modules:false,
        reasons:false,
        children:false,
        source:false,
        errors:false,
        errorDetails:false,
        warnings:false,
        publicPath:false
    },
    resolve:{  
        extensions:[  
            '.js',
            '.jsx',
            '.vue',
            '.ts',
            '.tsx'
        ],
        alias:{  

        }
    },
    externals:{  

    }
}

Also here some package versions that might be interesting

@symfony/webpack-encore@0.20.1
node-sass@4.9.0
sass-loader@7.0.3
webpack@3.12.0
Nemo64
  • 2,535
  • 3
  • 20
  • 24

3 Answers3

7

You can use Webpack aliases. Resolving every import /templates to your project's templates/ folder.

const path = require('path');

module.exports = {
  // ...
  resolve: {
    alias: {
      '/templates': path.resolve(__dirname, './templates')
    }
  }
};

I read @sympony/webpack-encore and found addAliases setting. You can use as the following example.

const path = require('path');
const Encore = require('@symfony/webpack-encore');

Encore
  // ...
  .addAliases({
    '/templates': path.resolve(__dirname, './templates')
  });

In your Scss/SASS on import use ~ ahead file path.

@import '~/templates/common/variables'
vsync
  • 118,978
  • 58
  • 307
  • 400
VitorLuizC
  • 360
  • 1
  • 7
1

Probably you already found the answer yourself, but just in case some else gets here the common way of using url() with paths relatives to the file where they are imported is using resolve-url-loader. Also note that you have to set the sourceMap to true in the preceding loaders.

https://www.npmjs.com/package/resolve-url-loader

That's an example on how to use it:

{
    // Note that sourceMap is needed to be true at least in sass-loader so resolve-url-loader works fine
    test: /\.scss$/,
    use: [
        {
            loader: "style-loader",
            options: { sourceMap: true }
        }, // Adds CSS to the DOM by injecting a <style> tag
        {
            loader: "css-loader",
            options: { sourceMap: true }
        }, // The css-loader interprets @import and url() like import/require() and will resolve them.
        {
            loader: "postcss-loader",
            options: {
                sourceMap: true,
                plugins: [
                    require("autoprefixer")({ browsers: ["last 2 versions"] })
                ]
            }
        }, // Adds prefix for cross-browser support
        {
            loader: "resolve-url-loader",
            options: { sourceMap: true }
        }, // Webpack loader that resolves relative paths in url() statements based on the original source file.
        {
            loader: "sass-loader",
            options: { sourceMap: true }
        } // Loads a Sass/SCSS file and compiles it to CSS.
    ]
}
Carlos Ruana
  • 2,138
  • 1
  • 15
  • 14
  • You are talking about a different problem. Sass imports other sass files within itself so the resolve-url-loader is way too late at that point. And I still haven't found a way to fix this. Less had a `paths` option. It seems that includePaths is what i'm looking for but its not working. I kind of accepted it at this point. – Nemo64 May 27 '19 at 08:01
0

I'm successfully using absolute imports with ~ and NODE_ENV set in .env

/.env:

NODE_PATH=src/

given that /src/styles/variables.scss exists, in any .scss file:

@import ~styles/variables`

works fine with CreateReactApp v2.0.

Ref: https://github.com/facebook/create-react-app/issues/4494#issuecomment-412113793

Varun Sukheja
  • 6,170
  • 5
  • 51
  • 93