Imported Sass file can't find font file - sass

I'm using gatsby-plugin-sass to include my sass files. I have a web-animations.sass file that imports _typography.sass. My _typography.sass has a font-face declaration like this:
#font-face
font-family: 'BrandonPrinted'
src: url(../../global/fonts/brandonprinted-one-webfont.eot)
src: url(../../global/fonts/brandonprinted-one-webfont.eot?#iefix) format('embedded-opentype'), url(../../global/fonts/brandonprinted-one-webfont.woff) format('woff'), url(/src/page-assets/global/fonts/brandonprinted-one-webfont.ttf) format('truetype')
When I run gatsby develop I get this error:
ERROR Failed to compile with 2 errors 19:51:15
These relative modules were not found:
* ../../global/fonts/brandonprinted-one-webfont.eot in ./~/css-loader!./~/sass-loader?{"plugins":[]}!./src/page-assets/work-ive-done/subpages/web-animations/styles/web-animations.sass
* ../../global/fonts/brandonprinted-one-webfont.woff in ./~/css-loader!./~/sass-loader?{"plugins":[]}!./src/page-assets/work-ive-done/subpages/web-animations/styles/web-animations.sass
It seems that the font url path is interpreted to be relative to web-animations.sassinstead of relative to _typography.sass because if I move web-animations.sass up two levels, then this error goes away.
Is there a way to have _typography.sass look for the font files relative to its own location?

Seems like this is resolved, but in case anyone runs across this in the future and wants an alternative solution I answered a similar question over here and included a repo with a deployed site demonstrating different ways of using static files with Sass.

I got this working by including the resolve-url-loader Webpack loader.
Here's my gatsby-node.js file:
"use strict";
var ExtractTextPlugin = require(`extract-text-webpack-plugin`);
var _require = require(`gatsby-1-config-css-modules`),
cssModulesConfig = _require.cssModulesConfig;
exports.modifyWebpackConfig = function (_ref, options) {
var config = _ref.config,
stage = _ref.stage;
var sassFiles = /\.s[ac]ss$/;
var sassModulesFiles = /\.module\.s[ac]ss$/;
options['sourceMap'] = 'sourceMap';
var sassLoader = `sass?${JSON.stringify(options)}`;
switch (stage) {
case `develop`:
{
config.loader(`sass`, {
test: sassFiles,
exclude: sassModulesFiles,
loaders: [`style`, `css`, 'resolve-url-loader', sassLoader]
});
return config;
}
case `build-css`:
{
config.loader(`sass`, {
test: sassFiles,
exclude: sassModulesFiles,
loader: ExtractTextPlugin.extract([`css?minimize`, 'resolve-url-loader', sassLoader])
});
config.loader(`sassModules`, {
test: sassModulesFiles,
loader: ExtractTextPlugin.extract(`style`, [cssModulesConfig(stage), 'resolve-url-loader', sassLoader])
});
return config;
}
case `develop-html`:
case `build-html`:
case `build-javascript`:
{
config.loader(`sass`, {
test: sassFiles,
exclude: sassModulesFiles,
loader: `null`
});
config.loader(`sassModules`, {
test: sassModulesFiles,
loader: ExtractTextPlugin.extract(`style`, [cssModulesConfig(stage), 'resolve-url-loader', sassLoader])
});
return config;
}
default:
{
return config;
}
}
};

Related

process.env.NODE_ENV variables into scss via webpack

Is there a way to reference a process.env.NODE_ENV in a scss file by passing it to the sass-loader in web-pack. If so anyone know how to go about this ?
Here is my webpack module lodaers array.
module: {
loaders: [
{ test: /\.js?$/,
loader: 'babel-loader',
include: path.join(__dirname, '../app'),
exclude: /node_modules/
},
{ test: /\.scss?$/,
loader: 'style-loader!css-loader!sass-loader',
include: path.join(__dirname, '../app', 'styles')
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
include : path.join(__dirname, '../app', 'images'),
loader : 'file-loader?limit=30000&name=[name].[ext]'
},
{
test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/,
include : path.join(__dirname, '../app', 'fonts'),
loader: 'file-loader?name=fonts/[name].[ext]'
}
]
I even tried
{ test: /\.scss?$/,
loader: 'style-loader!css-loader!sass-loader',
include: path.join(__dirname, '../app', 'styles'),
options: {
data: "$env: " + process.env.NODE_ENV + ";"
}
}
but the above broke the build.
I just want a way to access a url in my scss file depending on the environment.
It doesn't have to be via webpack any ideas would help without hard coding it.
for example:
.contact-transparent{
width: 100%;
height: 100%;
background: url(process.env.NODE_ENV+'/home-background.jpg') left center no-repeat;
}
I think you could get this done with a custom loader that you chain in before the others for your Sass files. In that loader you would check the value of NODE_ENV and do a find/replace in the Sass source, where the replaced value is based on the env. Not fancy but would get the job done. For example:
// url-by-env-loader.js
module.exports = (source) => {
const urlsByEnv = {
dev: "the-dev-host.com",
staging: "the-staging-host.com",
prod: "the-prod-host.com"
};
const urlToReplace = "the-url-in-your-sass-source.com";
const urlToUse = urlsByEnv[process.env.NODE_ENV];
const replaceRegex = new RegExp(urlToReplace, 'g');
return source.replace(replaceRegex, urlToUse);
}

extract text plugin not extracting css from .scss

I have the following webpack.cofig.js file
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: {
app: './src/main.ts',
polyfills: './src/polyfills.ts'
},
output: {
path: path.resolve('dist'),
filename: '[name].js',
publicPath: 'assets/'
},
resolve: {
// only discover files that have those extensions
extensions: ['.ts', '.js', '.json', '.css', '.scss', '.html'],
},
module: {
rules: [{
test: /\.ts$/,
exclude: /node_modules/,
loader: 'awesome-typescript-loader'
},
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'sass-loader']
})
},
{
test: /\.html$/,
loader: 'html-loader'
},
{
test: /\.(png|jpe?g|gif|svg|woff|woff2|ttf|eot|ico)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader?name=fonts/[name].[hash].[ext]?'
}
]
},
plugins: [
new ExtractTextPlugin({ filename: 'mystyle.css', disable: false, allChunks: true })
]
};
However when I run this, the css file that should be generated does not appear. I am using extract-text-webpack-plugin however this does not work. It does not throw an error, however it does not work either.
Ok I got this to work, the reason was that in my root app component (angular2) I had the following for referring to the main stylesheet.
styleUrls: ['./app.component.scss'],
This worked fine even without the scss loader (I am using the awesome typescript loader). However when I included the following
const styles = require('./app.component.scss');
Then the additional css got generated.

Webpack - how to configure base directory path for sass loader?

I'm trying to follow some tutorials and documentation and have the webpack build for me sass files into separates css files.
It all kind of works, as long as I'm proving full relative path in require:
require("../sass/ss.scss")
But it I want to use:
require("./ss.scss")
and I turn comment out the 'sassLoader' in the config, I get error:
[1] "sassLoader" is not allowed
As you can see I have been trying to use inline settings too:
sourceMap&includePaths[]=' + (PATHS.sass)
but they are ignored.
What am I doing wrong?
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const validate = require('webpack-validator');
const merge = require('webpack-merge');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const PATHS = {
app: path.join(__dirname, 'app'),
js: path.join(__dirname, 'app', 'js'),
sass: path.join(__dirname, 'app', 'sass'),
build: path.join(__dirname, 'build')
};
const common = {
// Entry accepts a path or an object of entries.
// We'll be using the latter form given it's
// convenient with more complex configurations.
entry: {
app: path.join(PATHS.js, 'index.js')
},
output: {
path: PATHS.build,
filename: '[name].js'
},
plugins: [
new HtmlWebpackPlugin({
title: 'Webpack demo'
}),
new ExtractTextPlugin(
'[name].css', {
allChunks: true
}
),
],
devtool: "source-map",
module: {
loaders: [
{
test: /\.scss$/,
loader: ExtractTextPlugin.extract(
'style!css?sourceMap!sass?sourceMap&includePaths[]=' + (PATHS.sass)
)
}
]
}
// sassLoader: {
// includePaths: [PATHS.sass]
// }
};
var config;
// Detect how npm is run and branch based on that
switch(process.env.npm_lifecycle_event) {
case 'build':
config = merge(common,
{}
);
break;
default:
config = merge(common,
{}
);
}
module.exports = validate(config);
The error comes from webpack-validator because it doesn't recognize the sassLoader property. You need to configure a schema extension:
const Joi = require('webpack-validator').Joi
const schemaExtension = Joi.object({
sassLoader: Joi.any(),
})
module.exports = validate(config, {schemaExtension: schemaExtension})
Requiring CSS modules is handled by the css-loader, only #import is handled by sass-loader. (There are major differences in their behaviour other than that, make sure you are using what you need).
In order to require from the root directory, you need to configure resolve.root in the webpack config file. See answer here: Resolving require paths with webpack

How Grunt watches children folder src, and putting output in same child dest?

I am new to NodeJs and Grunt, and I want to ask a question that is probably already answered, but I either couldn't understand solution, or couldn't find it.
So, I have www folder with many subfolders with projects. Every project has same folders inside,
--css/style.css
--sass/style.scss
--js/script.js + /1.js + /2.js
--build/script.js
--build/style.css
My Gruntfile.js with grunt is at www folder, and my grunt concat, goes something like this:
grunt.initConfig({
concat: {
dist: {
src: ['**/js/1.js', '**/js/2.js', '**/js/script.js'],
dest: '**/build/script.js'
},
},
});
Now, you can probably see the problem, I get error "Can't create directory C/wamp/www/** ..., and I need to be able to select same folder as where it found js (and later css and other tasks as well).
The most simple solution is needed, and I plan to use concat, watch, uglify, sass (solution for sass is welcome as well).
I am apologizing if this question is repeated, but I can't find an answer.
You cannot use a globbing pattern for your dest value, as globbing is for matching patterns. You will need a separate src -> dest mapping for each project subfolder. There are a few ways to do this, but I will use the Files Object Format. Assuming project subfolders named proj1/ and proj2/, the configuration would look like the following:
concat: {
dist: {
files: {
'proj1/build/script.js': 'proj1/js/*.js',
'proj2/build/script.js': 'proj2/js/*.js'
}
}
}
If you are going to keep adding project subfolders, it might make sense to build the concat configuration dynamically:
var project_dirs = ['proj1', 'proj2'];
var concat_config = {
dist: {}
};
concat_config.dist.files = project_dirs.reduce(function (memo, dir) {
var src = dir + '/js/*.js';
var dest = dir + '/build/script.js';
memo[dest] = src;
return memo;
}, {});
grunt.initConfig({
concat: concat_config
});
First
Concat and uglify your js:
concat.dev = {
files: {
"public/myapp.development.js": [
"with-bootstrap/public/js/vendor", "with-bootstrap/public/js/**/*.js"
]
}
};
//Uglify ===============================
config.uglify = {
dist: {
options: {
sourceMap: "public/myapp.production.js.map"
},
files: {
"public/myapp.production.js": ["public/myapp.development.js"]
}
}
}
and your sass:
//Sass ===============================
var sass;
config.sass = sass = {};
//distribution
sass.dist = {
options: {
style: "compressed",
noCache: true,
sourcemap: 'none',
update: true
},
files: {
"<%= src.distFolder %>": "<%= src.sassMain %>"
}
};
//development env.
sass.dev = {
options: {
style: "expanded",
lineNumber: true,
},
files: {
"<%= src.devFolder %>": "<%= src.sassMain %>"
}
};
watch your changes in that case I am watching just sass directory:
//Watch ===============================
config.watch = {
scripts: {
files: ["<%= src.libFolder %>", "<%= src.sassFolder %>"],
tasks: ["dev", "sass:dist"]
//,tasks: ["dev",'sass:dist']
}
}
anyway I hope that helps you for start.

Stop grunt-ts from compiling references

I've recently switched from using Web Essentials to grunt-ts to compile my typescript files due to the flexibility of output. Part of the reason I switched is that I don't want all files compiled seperately, and I don't want to have all files compiled to a single file. I want a bit of both. Since I've recently started using grunt for a lot of tasks, I thought I might as well switch my TS build too.
Here's my gruntfile
module.exports = function (grunt) {
grunt.initConfig({
pkg: grunt.file.readJSON('package.json'),
dirs: {
distribution: 'script/dist',
ts_root: 'script/src',
ts_controllers: 'script/src/controllers'
},
ts: {
apprunner: {
src: ['<%= dirs.ts_root %>/main.ts'],
out: '<%= dirs.distribution %>/src/main.js',
options: {
target: 'es5'
}
},
controllers: {
src: ['<%= dirs.ts_controllers %>/*.ts'],
out: '<%= dirs.distribution %>/src/controllers.js'
options: {
target: 'es5'
}
}
}
});
grunt.loadNpmTasks('grunt-ts');
grunt.registerTask('default', ['ts']);
};
Inside the main.ts file, I have to reference one of the typescript files that, when compiled, makes up part of the controllers.js file.
So my main.js file I have the following:
/// <reference path="controllers/ExampleController.ts" />
var newExample = new wctApp.controllers.ExampleController();
Grunt compiles my controllers.js file fine:
var wctApp;
(function (wctApp) {
(function (controllers) {
var ExampleController = (function () {
function ExampleController() {
}
return ExampleController;
})();
controllers.ExampleController = ExampleController;
})(wctApp.controllers || (wctApp.controllers = {}));
var controllers = wctApp.controllers;
})(wctApp || (wctApp = {}));
But it compiles the same code inside the main.js file.
var wctApp;
(function (wctApp) {
(function (controllers) {
var ExampleController = (function () {
function ExampleController() {
}
return ExampleController;
})();
controllers.ExampleController = ExampleController;
})(wctApp.controllers || (wctApp.controllers = {}));
var controllers = wctApp.controllers;
})(wctApp || (wctApp = {}));
;
var newExample = new wctApp.controllers.ExampleController();
If I remove the reference from the main file, it won't build because it can't find ExampleController. How can I keep the reference to this file, but stop it from being compiled in the main.js file.
Don't use out. Because out merges all the TypeScript files into one. Instead use outDir (if you need to redirect to a different folder). Or better don't use anything (no out no outDir) and it will put the generated JS next to the file.

Resources