En mi proyecto, uso algunos recursos (principalmente imágenes) tanto en SASS como en Blade. Además, tengo algunos recursos que solo se usan en SASS, y otros que solo se usan en Blade.
Por ejemplo, podría usar mix('images/logo.png')
en archivos Blade y background: url('../images/logo.png')
en archivos SASS.
En cuanto a la estructura de mi directorio, hice lo siguiente:
- resources
- js
- sass
- images // All images used by Blade, Sass, or both
- fonts
Para compilar mis recursos y colocarlos en la public
carpeta, utilizo lo siguiente webpack.mix.js
:
mix.copy('resources/images/**/*.*', 'public/images');
mix.copy('resources/fonts/**/*.*', 'public/fonts');
mix.version('public/images/**/*.*');
mix.version('public/fonts/**/*.*');
mix.js('resources/js/app.js', 'public/js')
.js('resources/js/vendor.js', 'public/js')
.scripts([ // Old not ES6 JS
'resources/js/tpl/core.min.js'
], 'public/js/core.min.js')
.sass('resources/sass/app.scss', 'public/css')
.sourceMaps()
.version();
Como resultado, obtengo esa URL en app.css:
background: url(/images/logo.png?0e567ce87146d0353fe7f19f17b18aca);
Mientras obtengo otro en HTML renderizado:
src="/images/logo.png?id=4d4e33eae039c367c8e9"
Se consideran 2 recursos diferentes, eso no es lo que esperaba ...
Posible solución
Descubrí que los archivos CSS generados por el uso SASS un versionado URL incluso si no especifico version()
en webpack.mix.js
. Entonces me preguntaba si tal vez podría usar algún truco, como este:
const sass = require('sass');
// Custom SASS function to get versioned file name
// Uses Mix version md5 hash
const functions = {
'versioned($uri)': function(uri, done) {
uri = uri && uri.getValue() || uri;
const version = File.find(path.join(Config.publicPath, uri)).version();
done(new sass.types.String(`${uri}?id=${version}`));
}
};
mix.sass('resources/sass/all.scss', 'public/css', {
sassOptions: {
functions
}
})
.options({ // Do not process URLs anymore
processCssUrls: false
});
Y úsalo en SASS así:
background-image: url(versioned('/images/logo.png'));
Pero esta solución tiene muchos inconvenientes, estoy obligado a usar la versioned
función cada vez, mi código fuente no funcionará fácilmente en otros proyectos sin la webpack.mix.js
función, y tengo que editar todos los archivos que uso en mi carpeta de recursos para usar la función.
Otra solución?
Creo que la fuente de mi problema podría provenir de la forma en que estructuré mis archivos, tengo una resources/images
carpeta que contiene imágenes utilizadas por SASS pero también utilizadas por Blade.
Las imágenes utilizadas en SASS se copiarán public/images
porque esa es la forma en que SASS funciona con el paquete web, y estas imágenes también se copiarán una segunda vez porque lo usé mix.copy()
(porque necesito que los otros archivos estén dentro de la carpeta pública para poder acceder a ellos en Blade / HTML).
Estoy bastante seguro de que me estoy equivocando en alguna parte, busqué en Internet una forma adecuada de trabajar con los recursos de SASS y Blade en Laravel, pero no encontré nada relevante.
¿Quizás debería considerar otra estructura de archivos? Pero cual ?
mix.version()
y para los archivos CSS, hay su propio cargador de archivos con su propia función de hash. No tiene nada en común con la estructuración de archivos. Su solución propuesta parece ser una buena opción, no creo que haya una solución nativa para este problema.Respuestas:
La reescritura
url()
dentro de las hojas de estilo es una característica del paquete web , agrega el hash MD5 calculado del archivo a la URL.mix.version()
por otro lado genera un hash diferente gracias a esas líneas:Laravel Mix lee el archivo como una cadena (no como un búfer), lo codifica y extrae solo los primeros 20 caracteres. No puedo encontrar una manera simple de anular este comportamiento, una solución rápida y sucia es redefinir la
hash
función:Una mejor manera es extender Laravel Mix y definir su propio
versionMD5()
método, puede copiar algún código de esta extensión .fuente