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
Related
I started to write library to fetch some data from an api in typescript and use webpack as a bundler.
We have a dev, test and prod api, so the lib should use differnt urls for each environment.
Webpack has the normalModuleReplacmentPlugin build in, to replace files, depending on the configuration. I created different environment files, which should be replaced by webpack.
I'm using Ubuntu 18.04, but one of our developer which is now working on the lib currently using windows. He noticed that the replacement is not working on his local machine.
webpack.config.js (example from my github repo)
const merge = require( 'webpack-merge' );
const path = require( 'path' );
const commonConfigObj = {
entry: {
'fooBar': './src/index.ts'
},
output: {
filename: '[name].js',
path: path.resolve( __dirname, 'dist' ),
library: 'FooBar',
libraryTarget: 'umd'
},
module: {
rules: [
{
test: /\.tsx?$/,
use: [
{
loader: 'ts-loader',
options: { configFile: 'tsconfig.json' }
}
]
}
]
},
resolve: {
extensions: [ '.ts', '.tsx', '.js' ]
},
profile: true
};
const commonConfig = merge( [ commonConfigObj ] );
const environments = {
'prod': require( './webpack/prod.config.js' ),
'dev': require( './webpack/dev.config.js' )
};
module.exports = mode=>{
if( mode ) {
const envConfig = environments[ mode.env ];
if( envConfig ) {
return merge( commonConfig, envConfig );
}
}
return merge( commonConfig, environments.dev );
};
webpack/prod.config.js (example from my github repo)
const CleanWebpackPlugin = require( 'clean-webpack-plugin' );
const BundleAnalyzerPlugin = require( 'webpack-bundle-analyzer' ).BundleAnalyzerPlugin;
const webpack = require('webpack');
module.exports = {
mode: 'production',
plugins: [
new CleanWebpackPlugin(),
new BundleAnalyzerPlugin( {
analyzerMode: 'disabled',
generateStatsFile: true
} ),
new webpack.NormalModuleReplacementPlugin(
/src\/environments\/environment.ts/,
'./environment.prod.ts'
),
],
devtool: 'source-map'
};
I'm sure that this is not a webpack issue but wrong usage.
GitHub repo: https://github.com/ManticSic/normalModuleReplacmentPlugin-issue-windows
Run npm ci and npm run build (or npm run build-dev for dev env).
You can find the important part at the end of line #1
expected: ...,t.environment={bar:"Prod"}...
result on windows: ...,t.environment={bar:"Normal"}...
Like expected the problem was sitting in front of the computer...
Wrong file system separators were used.
Replacing \/ with [\\\/] works fine!
Full regex: /src[\\\/]environments[\\\/]environment.ts/
This is my first time build a webpack.production.config.js file. Here is my directory structure.
My webpack dev config entry and output is as follows:
const path = require('path');
const webpack = require('webpack');
let config = {
entry: path.resolve(__dirname, 'app/index.js'),
output: {
path: path.resolve(__dirname, '/public'),
filename: 'bundle.js',
},
....
My webpack production file is this:
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
entry: path.resolve(__dirname, 'app/index.js'),
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].js',
},
module: {
loaders: [
{ test: /\.json$/, loader: 'json' },
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
{
test: /\.css$/,
use: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' }),
},
{ test: /\.(png|svg|jpg|gif)$/, use: ['file-loader'] },
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader'],
},
],
},
plugins: [
new HtmlWebpackPlugin({ title: 'My App', filename: 'admin.html' }),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify('production'),
}),
new webpack.optimize.UglifyJsPlugin(),
new ExtractTextPlugin('styles.css'),
new webpack.optimize.CommonsChunkPlugin('common.js'),
],
};
Npm start works fine. Npm run build compiles and creates my build folder. In the folder are my assets, a main.js, common.js.js, and admin.html generated from the HtmlWebpackPlugin.
When built, the admin.html is reading the commmon.js.js and main.js sources.
As I try to deploy to heroku, How to get my output paths in production correct so the new generated html is in the root and reads the proper js files? Currently in my package.json, the entry point is "app/index.js".
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);
}
I want to reduce the size of my bundle more after doing the source-map and CommonChunk.
Let say I am using react-d3 library. But only the D3.PieChart is used throughout the whole application.
// only PieChart is used
var PieChart = require('rd3').PieChart
When I look into the bundle file, all other components like BarChart, blah blah are also included. Is there anyway to only include the PieChart part of react-d3 library? Same case for react and react-router, anyway to only import a portion of the library but not whole.
I am using Webpack for bundling.
Here is my webpack config:
var Webpack = require('webpack')
var DevelopmentEnvironmentConfig = new Webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('development'),
}
})
var CommonChunkConfig = new Webpack.optimize.CommonsChunkPlugin({
name: "vendor",
filename: "vendor_bundle.js",
minChunks: 4
})
module.exports = {
devtool: 'eval',
entry: {
app: './src/index.js',
vendor: ['react', 'react-router', 'react-dom', 'd3', 'rd3']
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
loader: "babel-loader"
}
]
},
output: {
filename: "app_bundle.js",
path: __dirname + '/public/javascripts/'
},
plugins: [DevelopmentEnvironmentConfig, CommonChunkConfig]
}
Currently, I use webpack to build a single JS file which represents my app. How do I split my React app UI shell from rest of the app logic, so that I can have the service Worker cache it?
My webpackpack config file looks like this, that generates a single index_bundle.js file(no css file):
import webpack from 'webpack'
import path from 'path'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import autoprefixer from 'autoprefixer'
const LAUNCH_COMMAND = process.env.npm_lifecycle_event
const isProduction = LAUNCH_COMMAND === 'production'
process.env.BABEL_ENV = LAUNCH_COMMAND
const PATHS = {
root: path.join(__dirname),
app: path.join(__dirname, 'app'),
build: path.join(__dirname, 'dist')
}
const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
template: PATHS.app + '/index.html',
filename: 'index.html',
inject: 'body'
})
const productionPlugin = new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
})
const productionPlugin2 = new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
})
const base = {
entry: [
'babel-polyfill',
PATHS.app
],
output: {
path: PATHS.build,
filename: 'index_bundle.js'
},
module: {
loaders: [
{test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
{test: /\.css$/, loader: 'style!css?sourceMap&modules&localIdentName=[name]__[local]___[hash:base64:5]&importLoader=1!postcss'}
]
},
postcss: [ autoprefixer({ browsers: ['last 2 versions'] }) ],
resolve: {
root: path.resolve('./app')
}
}
const developmentConfig = {
devtool: 'cheap-module-inline-source-map',
devServer: {
contentBase: PATHS.build,
historyApiFallback: true,
hot: true,
inline: true,
progress: true
},
plugins: [HTMLWebpackPluginConfig, new webpack.HotModuleReplacementPlugin()]
}
const productionConfig = {
devtool: 'cheap-module-source-map',
plugins: [HTMLWebpackPluginConfig, productionPlugin, productionPlugin2]
}
export default Object.assign({}, base, isProduction === true ? productionConfig : developmentConfig)
My "Instant Loading with Service Workers" talk from the Chrome Dev Summit 2015 covers creating a PWA using the App Shell + dynamic model, powered by React.
The code sample for it is part of the sw-precache library's repo: https://github.com/GoogleChrome/sw-precache/tree/master/app-shell-demo
(It's not necessarily the most idiomatic React code in the world, but the general concepts, especially when it comes to the service worker implementation, should hold.)