rutas relativas otra carpeta absolutas css less asp.net-mvc-5 bundletransformer

css - otra - Stop Bundle Transformer convierte rutas relativas en LESS



rutas relativas css (2)

En los módulos BundleTransformer.Less y BundleTransformer.SassAndScss no se puede deshabilitar la transformación de rutas relativas a absolutas, ya que puede romper las referencias a las imágenes cuando se utilizan las directivas @import .

Para obtener /img/logo.png lugar de /css/img/logo.png solo necesita especificar correctamente una ruta relativa en el código fuente ( ../../img/logo.png lugar de ../img/logo.png ).

Estoy usando Bundle Transformer para la compilación LESS en un proyecto MVC5. El paquete My LESS consta de un solo archivo main.less que importa otros archivos ubicados en subcarpetas. Algunos de los archivos contienen referencias a archivos de imagen como ese; está en el archivo /css/structure/header.less :

.site__logo { background: url(''../img/logo.png'') no-repeat; // ... }

En el paquete compilado ( /css/lessBundle ) esto se convierte en:

background: url(''/css/img/logo.png'') no-repeat;

Deseo que la ruta relativa en el archivo .less se conserve cuando se incluye para que apunte correctamente a /img/logo.png , no a /css/img/logo.png . Creo que Bundle Transformer es responsable de convertir las rutas relativas; la documentación tiene este párrafo, pero no entra en más detalles:

También debe comprender que cuando conecta instancias de clases de CssTransformer y JsTransformer, conecta un conjunto de transformaciones (elección entre versiones depuradas y preminificadas de archivos, código de traducción de los lenguajes intermedios, minificación de código de tiempo de ejecución, transformación de rutas a absoluto (solo para código CSS) y combinación de código). Un conjunto de transformaciones depende de los módulos de Bundle Transformer que haya instalado y de la configuración que haya especificado en el archivo Web.config.

Aquí está mi BundleConfig:

public class BundleConfig { public const string LessBundlePath = "~/css/lessBundle"; public static void RegisterBundles(BundleCollection bundles) { var nullBuilder = new NullBuilder(); var cssTransformer = new CssTransformer(); var nullOrderer = new NullOrderer(); // Skip JS-related stuff var lessBundle = new Bundle(LessBundlePath) .Include("~/css/main.less"); lessBundle.Builder = nullBuilder; lessBundle.Transforms.Add(cssTransformer); lessBundle.Orderer = nullOrderer; bundles.Add(lessBundle); BundleTable.EnableOptimizations = true; } }

/css/main.less es principalmente solo un montón de importaciones:

@import "bootstrap/bootstrap"; @import "structure/header"; // etc. html, body { height: 100%; }

He intentado jugar con esta configuración en web.config, pero sin ningún efecto:

<css defaultMinifier="NullMinifier" disableNativeCssRelativePathTransformation="true">

Si es posible, preferiría no modificar los filepaths en los archivos .less, ya que son proporcionados por un tercero y todo funciona bien en su servidor de integración (que no usa .NET). ¿Hay algo mas que pueda hacer?


Resolví esto hace un tiempo, antes de que MVC tuviera algún tipo de soporte para archivos LESS. Acabo de probar para verificar, y esta clase aplicará correctamente la carpeta actual de @imported .less al transformarla en CSS.

BundleHelper.cs:

using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Text; using System.Web; using System.Web.Hosting; using System.Web.Optimization; using dotless.Core; using dotless.Core.Abstractions; using dotless.Core.Importers; using dotless.Core.Input; using dotless.Core.Loggers; using dotless.Core.Parser; public static class BundleHelper { internal class LessBundle : StyleBundle { public LessBundle(string virtualPath) : base(virtualPath) { // inject LessTransform to the beginning of the Transforms Transforms.Insert(0, new LessTransform()); } public LessBundle(string virtualPath, string cdnPath) : base(virtualPath, cdnPath) { // inject LessTransform to the beginning of the Transforms Transforms.Insert(0, new LessTransform()); } } // TODO: speed improvement - consider not parsing any CSS files that are not LESS // TODO: verify that this still works for nested @imports internal class LessTransform : IBundleTransform { public void Process(BundleContext context, BundleResponse bundle) { if (context == null) throw new ArgumentNullException("context"); if (bundle == null) throw new ArgumentNullException("bundle"); context.HttpContext.Response.Cache.SetLastModifiedFromFileDependencies(); // initialize variables var lessParser = new Parser(); ILessEngine lessEngine = CreateLessEngine(lessParser); var content = new StringBuilder(bundle.Content.Length); var bundleFiles = new List<BundleFile>(); foreach (var bundleFile in bundle.Files) { bundleFiles.Add(bundleFile); // set the current file path for all imports to use as the working directory SetCurrentFilePath(lessParser, bundleFile.IncludedVirtualPath); using (var reader = new StreamReader(bundleFile.VirtualFile.Open())) { // read in the LESS file string source = reader.ReadToEnd(); // parse the LESS to CSS content.Append(lessEngine.TransformToCss(source, bundleFile.IncludedVirtualPath)); content.AppendLine(); // add all import files to the list of bundleFiles ////bundleFiles.AddRange(GetFileDependencies(lessParser)); } } // include imports in bundle files to register cache dependencies if (BundleTable.EnableOptimizations) bundle.Files = bundleFiles.Distinct(); bundle.ContentType = "text/css"; bundle.Content = content.ToString(); } /// <summary> /// Creates an instance of LESS engine. /// </summary> /// <param name="lessParser">The LESS parser.</param> private ILessEngine CreateLessEngine(Parser lessParser) { var logger = new AspNetTraceLogger(LogLevel.Debug, new Http()); return new LessEngine(lessParser, logger, true, false); } // TODO: this is not currently working and may be unnecessary. /// <summary> /// Gets the file dependencies (@imports) of the LESS file being parsed. /// </summary> /// <param name="lessParser">The LESS parser.</param> /// <returns>An array of file references to the dependent file references.</returns> private static IEnumerable<BundleFile> GetFileDependencies(Parser lessParser) { foreach (var importPath in lessParser.Importer.Imports) { var fileName = VirtualPathUtility.Combine(lessParser.FileName, importPath); var file = BundleTable.VirtualPathProvider.GetFile("~/Content/test2.less"); yield return new BundleFile(fileName, file); } lessParser.Importer.Imports.Clear(); } /// <summary> /// Informs the LESS parser about the path to the currently processed file. /// This is done by using a custom <see cref="IPathResolver"/> implementation. /// </summary> /// <param name="lessParser">The LESS parser.</param> /// <param name="currentFilePath">The path to the currently processed file.</param> private static void SetCurrentFilePath(Parser lessParser, string currentFilePath) { var importer = lessParser.Importer as Importer; if (importer == null) throw new InvalidOperationException("Unexpected dotless importer type."); var fileReader = importer.FileReader as FileReader; if (fileReader != null && fileReader.PathResolver is ImportedFilePathResolver) return; fileReader = new FileReader(new ImportedFilePathResolver(currentFilePath)); importer.FileReader = fileReader; } } public class ImportedFilePathResolver : IPathResolver { private string _currentFileDirectory; private string _currentFilePath; public ImportedFilePathResolver(string currentFilePath) { if (String.IsNullOrEmpty(currentFilePath)) throw new ArgumentNullException("currentFilePath"); CurrentFilePath = currentFilePath; } /// <summary> /// Gets or sets the path to the currently processed file. /// </summary> public string CurrentFilePath { get { return _currentFilePath; } set { var path = GetFullPath(value); _currentFilePath = path; _currentFileDirectory = Path.GetDirectoryName(path); } } /// <summary> /// Returns the absolute path for the specified imported file path. /// </summary> /// <param name="filePath">The imported file path.</param> public string GetFullPath(string filePath) { if (filePath.StartsWith("~")) filePath = VirtualPathUtility.ToAbsolute(filePath); if (filePath.StartsWith("/")) filePath = HostingEnvironment.MapPath(filePath); else if (!Path.IsPathRooted(filePath)) filePath = Path.GetFullPath(Path.Combine(_currentFileDirectory, filePath)); return filePath; } } }

Ejemplo de uso:

  • App_Start / BundleConfig.cs:

    public class BundleConfig { public static void RegisterBundles(BundleCollection bundles) { bundles.Add(new BundleHelper.LessBundle("~/Content/css").Include( "~/Content/normalStuff.css", "~/Content/template.less", "~/Content/site.less")); } }

  • Contenido / template.less:

    @import "themes/blue/test"; body { background: url(''../img/logo.png'') no-repeat; } footer { background: url(''img/logo1.png'') no-repeat; }

  • Contenido / themes / blue / test.less:

    .myTheme { background: url(''../img/logo2.png'') no-repeat; } .myTheme2 { background: url(''img/logo3.png'') no-repeat; }

El uso de este paquete generará el siguiente CSS, que debería ser exactamente lo que está buscando:

  • ubicación: example.com/path/Content/test.less

    .myTheme { background: url(''themes/img/logo2.png'') no-repeat; } .myTheme2 { background: url(''themes/blue/img/logo3.png'') no-repeat; } body { background: url(''../img/logo.png'') no-repeat; } footer { background: url(''img/logo1.png'') no-repeat; }

NOTA: En base a los comentarios anteriores míos, no estoy seguro de qué tan bien manejará @imports anidados (las importaciones dentro de la test.less sin embargo, a una carpeta diferente)

Avíseme si esto no funciona para usted.