Webpack4 : Moving / Importing Image Folder from "SRC folder" to "DIST folder" - image

I'm trying to import (move) my image folder from my src folder to my dist folder with Webpack 4 but unlike Gulp, this task looks SO complicated in Webpack even when I'm not even trying to mess around with the images at the moment, I just want Webpack to load them and put them on my dist/image folder.
I've seen that people import image by image on their index.js which I refuse to believe is the only solution, is there a way to just move the whole folder to the dist / production folder without having to import file by file on the index.js ?
This is my webpack config at the moment:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
entry: path.resolve(__dirname, 'src/js/scripts.js'),
output: {
path: path.resolve(__dirname,'dist'),
filename: '[name].[chunkhash].js'
},
module: {
rules: [
//JS
{
//Tipo de Archivo quiero reconocer
test: /\.js$/,
exclude: /node_modules/,
//Que Loader se encarga del tipo de extension de archivo
use: {
loader: 'babel-loader',
options: {
presets:['babel-preset-env']
}
},
},
//IMAGES
{
test: /\.(jpg|png|gif)$/,
use: {
loader: 'file-loader',
options: {
outputPath: 'images/',
name:'[name][hash].[ext]',
}
}
},
//SASS
{
test: /\.scss$/,
use: ['style-loader', MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader', 'sass-loader']
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename:'css/style.min.[contenthash].css',
}),
new HtmlWebpackPlugin ({
inject: false,
hash: true,
template: './src/index.html',
filename: 'index.html'
}),
new WebpackMd5Hash()
]
}
I'm not pasting my index.js file because I just don't know what to do there since I won't be importing image by image. Looking forward for your thoughts.

The following statement should output all images in folder images to dist.
require.context("../images/", true, /\.(png|svg|jpg|gif)$/);

Related

How to best optimize initial page load for react web app with images especially for mobile?

I have a fairly complex web app written in React/Redux and webpack for compilation. Its landing page consists of 2 images and the main app module. All the other modules are lazy-loaded depending on what the user wants to do. When I audit using google devtools, I get a performance score of 74, which isn't bad.
But the initial page loads in over 15 seconds on the iphones! And I need to optimize it.
Images One of the images is the background of html body, so that it shows when other pages are loading. The other one is the background of the Home page component. The home page image is non-negotiable, it must be there. The one in the body I'm more flexible about, but it looks cool.
Right now the Home page image is imported into the react component using the webpack url-loader and is therefore in the app bundle. Is that the best way? The other image is loaded in the index.html on the body element directly. I'm not sure which is the fastest way.
I'm not an image expert either, so maybe is there something else I can do to compress or optimize the images? Is there a "best size" for use cross-platform? Also what tools to use to change? I have GIMP on my system, but can use something else.
Splash It would be nice if the user sees "something" when it's loading right away, so they can be more patient. Right now they only see a blank white screen. I have following all the favicon generator and have them all setup according to directions. But the splash is not showing. Is there something I can do there? I have even tried to alter right in the HTML a different color background, but that doesn't show up either.
CSS To organize my project code, I built everything very componentized. My stylesheets mostly sit alongside each component and are imported into where it's used. These also get bundled by webpack using miniCssExtractLoader and css-loader. I attach my webpack configs -- is there something I can do there?
Webpack What else can I do to get the initial load time down? Here are my webpack.common and webpack.prod setups. Any ideas will be appreciated!
webpack.common.js
const path = require('path');
var webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const sourcePath = path.join(__dirname, './src');
const autoprefixer = require('autoprefixer');
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js'
},
output: {
filename: '[name].[chunkhash:4].js',
chunkFilename: '[name].[chunkhash:4].js', //name of non-entry chunk files
path: path.resolve(__dirname, 'dist'), //where to put the bundles
publicPath: "/" // This is used to generate URLs to e.g. images
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: "babel-loader"
}
},
{
test: /\.html$/,
use: [
{
loader: "html-loader",
options: { minimize: true }
}
]
},
{
test: /\.(scss|sass|css)$/,
use: [
MiniCssExtractPlugin.loader,
{ loader: 'css-loader' },
{ loader: 'postcss-loader',
options: {
plugins: () => [autoprefixer({ grid: false})]
}
},
{
loader: 'fast-sass-loader',
options: {
includePaths: [ path.resolve(__dirname, 'src'), path.resolve(__dirname, 'src','styles') ,'./node_modules', '/node_modules/materialize-css/sass/components'],
sourceMap: true
}
}
]
},
{
test: /\.(jpg|png)$/,
loader: 'url-loader',
options: {
limit: 8192 // inline base64 URLs for <=8k images, direct URLs for the rest
},
},
{
test: /\.svg/,
use: {
loader: 'svg-url-loader',
options: {}
}
}
]
},
resolve: {
alias: {
components: path.resolve(__dirname, 'src', 'components'),
navigation: path.resolve(__dirname, 'src', 'navigation'),
reducers: path.resolve(__dirname, 'src', 'reducers'),
actions: path.resolve(__dirname, 'src', 'actions'),
routes: path.resolve(__dirname, 'src', 'routes'),
utils: path.resolve(__dirname, 'src', 'utils'),
styles: path.resolve(__dirname, 'src', 'styles'),
images: path.resolve(__dirname, 'public', 'images'),
public: path.resolve(__dirname, 'public'),
test: path.resolve(__dirname, 'src', 'test'),
materialize: path.resolve(__dirname, 'node_modules', 'materialize-css', 'sass', 'components')
},
// extensions: ['.webpack-loader.js', '.web-loader.js', '.loader.js', '.js', '.jsx'],
modules: [
path.resolve(__dirname, 'node_modules'),
sourcePath
]
},
optimization: {
splitChunks: {
cacheGroups: {
js: {
test: /\.js$/,
name: "commons",
chunks: "all",
minChunks: 7,
},
styles: {
test: /\.(scss|sass|css)$/,
name: "styles",
chunks: "all",
enforce: true
}
}
}
},
plugins: [
new CleanWebpackPlugin(['dist']),
new CopyWebpackPlugin([ { from: __dirname + '/public', to: __dirname + '/dist/public' } ]),
new MiniCssExtractPlugin({filename: "[name].css"}),
new webpack.NamedModulesPlugin(),
new HtmlWebpackPlugin({
"template": "./src/template.html",
"filename": "index.html",
"hash": false,
"inject": true,
"compile": true,
"favicon": false,
"minify": true,
"cache": true,
"showErrors": true,
"chunks": "all",
"excludeChunks": [],
"title": "ShareWalks",
"xhtml": true,
"chunksSortMode": 'none' //fixes bug
})
]
};
webpack.prod.js
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const WorkboxPlugin = require('workbox-webpack-plugin');
module.exports = merge(common, {
mode: 'production',
devtool: 'source-map',
plugins: [
new WorkboxPlugin.GenerateSW({
// these options encourage the ServiceWorkers to get in there fast
// and not allow any straggling "old" SWs to hang around
clientsClaim: true,
skipWaiting: true
}),
]
});
Your question is too broad for SO and will be closed :) Lets concentrate on "how to make bundle smaller" optimization path.
1.try babel loose compilation (less code)
module.exports = {
"presets": [
["#babel/preset-env", {
// ...
"loose": true
}]
],
}
2.also review your polyfills, use minification, learn webpack null-loader techique.
3.there is a hope that more aggresive chunking could give some positive effect (if not all is used on each your app page, then it can be lazy loaded).
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
maxInitialRequests: infinity,
cacheGroups: {
vendor: {
test: /[\\/]node_modules[\\/]/,
vendorname(v) {
var name = v.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1];
return `npm.${name.replace('#', '_')}`;
},
},
},

Laravel + VueJs + Webpack + Karma = world of pain

Is it possible to write unit tests for VueJs if you are using Laravel's Elixir for your webpack configuration?
VueJs 2x has a very simple example for a component test: Vue Guide Unit testing
<template>
<span>{{ message }}</span>
</template>
<script>
export default {
data () {
return {
message: 'hello!'
}
},
created () {
this.message = 'bye!'
}
}
</script>
and then...
// Import Vue and the component being tested
import Vue from 'vue'
import MyComponent from 'path/to/MyComponent.vue'
describe('MyComponent', () => {
it('has a created hook', () => {
expect(typeof MyComponent.created).toBe('function')
})
it ...etc
})
and gives an example of a karma conf file here: https://github.com/vuejs-templates
But the Karma configuration file requires a webpack configuration file
webpack: webpackConfig,
The only problem is the Laravel's Elixir is creating the webpack configuration so it can't be included.
I have tried creating another webpack configuration file based on the example from https://github.com/vuejs-templates/webpack.
Something like this:
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
// Since sass-loader (weirdly) has SCSS as its default parse mode, we map
// the "scss" and "sass" values for the lang attribute to the right configs here.
// other preprocessors should work out of the box, no loader config like this necessary.
'scss': 'vue-style-loader!css-loader!sass-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax'
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}
and included it like...
// Karma configuration
// Generated on Wed Mar 15 2017 09:47:48 GMT-0500 (CDT)
var webpackConf = require('./karma.webpack.config.js');
delete webpackConf.entry;
module.exports = function(config) {
config.set({
webpack: webpackConf, // Pass your webpack.config.js file's content
webpackMiddleware: {
noInfo: true,
stats: 'errors-only'
},
But I am getting errors that seem to indicate that webpack isn't doing anything.
ERROR in ./resources/assets/js/components/test.vue
Module parse failed: /var/www/test/resources/assets/js/components/test.vue Unexpected token (1:0)
You may need an appropriate loader to handle this file type.
| <template>
| <span >{{test}}</span>
| </template>
Ok, I got this to work. Couple of things that might help.
I was originally running gulp, and trying to run tests in my vagrant box, to try to match the server configuration. I think that makes it much harder to find examples and answers on the internet.
Ok, so the main problem I was having is that webpack wasn't processing my components included in my test files. I copied the webpack config out of the laravel-elixir-vue-2/index.js node module directly into the Karma configuration file and it started working.
The key is that karma-webpack plugin needs both the resolve and module loader configuration settings (resolve with alias and extensions) for it to work.
Hope this helps someone.
karma.conf.js:
module.exports = function (config) {
config.set({
// to run in additional browsers:
// 1. install corresponding karma launcher
// http://karma-runner.github.io/0.13/config/browsers.html
// 2. add it to the `browsers` array below.
browsers: ['Chrome'],
frameworks: ['jasmine'],
files: ['./index.js'],
preprocessors: {
'./index.js': ['webpack']
},
webpack: {
resolve: {
alias: {
vue: 'vue/dist/vue.common.js'
},
extensions: ['.js', '.vue']
},
vue: {
buble: {
objectAssign: 'Object.assign'
}
},
module: {
loaders: [
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'file-loader',
query: {
limit: 10000,
name: '../img/[name].[hash:7].[ext]'
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
query: {
limit: 10000,
name: '../fonts/[name].[hash:7].[ext]'
}
}
]
}
},
webpackMiddleware: {
noInfo: true,
},
coverageReporter: {
dir: './coverage',
reporters: [
{ type: 'lcov', subdir: '.' },
{ type: 'text-summary' },
]
},
});
};
I ran into the exact same problem. The accepted answer did not fully work for me. The following solved my issue:
Install relevant loaders for webpack:
npm install --save-dev vue-loader file-loader url-loader
Create webpack config file (note the format). The accepted answer produced errors citing invalid format of the webpack.config.js file. At least with me it did.
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.vue$/,
use: [
{ loader: 'vue-loader' }
]
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
use: [
{
loader: 'file-loader',
query: {
limit: 10000,
name: '../img/[name].[hash:7].[ext]'
}
}
]
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
use: [
{
loader: 'url-loader',
query: {
limit: 10000,
name: '../fonts/[name].[hash:7].[ext]'
}
}
]
}
]
}
}
karma.conf.js
// Karma configuration
var webpackConf = require('./webpack.config.js');
delete webpackConf.entry
module.exports = function(config) {
config.set({
frameworks: ['jasmine'],
port: 9876, // web server port
colors: true,
logLevel: config.LOG_INFO,
reporters: ['progress'], // dots, progress
autoWatch: true, // enable / disable watching files & then run tests
browsers: ['Chrome'], //'PhantomJS', 'Firefox',
singleRun: true, // if true, Karma captures browsers, runs the tests and exits
concurrency: Infinity, // how many browser should be started simultaneous
webpack: webpackConf, // Pass your webpack.config.js file's content
webpackMiddleware: {
noInfo: true,
stats: 'errors-only'
},
/**
* base path that will be used to resolve all patterns (eg. files, exclude)
* This should be your JS Folder where all source javascript
* files are located.
*/
basePath: './resources/assets/js/',
/**
* list of files / patterns to load in the browser
* The pattern just says load all files within a
* tests directory including subdirectories
**/
files: [
{pattern: 'tests/*.js', watched: false},
{pattern: 'tests/**/*.js', watched: false}
],
// list of files to exclude
exclude: [
],
/**
* pre-process matching files before serving them to the browser
* Add your App entry point as well as your Tests files which should be
* stored under the tests directory in your basePath also this expects
* you to save your tests with a .spec.js file extension. This assumes we
* are writing in ES6 and would run our file through babel before webpack.
*/
preprocessors: {
'app.js': ['webpack', 'babel'],
'tests/**/*.spec.js': ['babel', 'webpack']
},
})
}
Then run karma start and everything should work.

Webpack and SASS sourcemaps paths issue

I've make a very simple project to ilustrate the problem.
The project structure is:
The contents of webpack.config.js:
var path = require('path');
module.exports = {
entry: [
'./src/main.js',
'./src/main.scss'
],
output: {
path: path.join(__dirname, 'www/'),
filename: 'bundle.js'
},
module: {
loaders: [{
loaders: ['style-loader', 'css-loader?sourceMap', 'sass-loader?sourceMap'],
test: /\.scss$/
}]
},
devtool: 'source-map',
devServer: {
contentBase: 'www/'
}
};
The bundle generation is working properly, but when I debug the application, the SASS sourcemaps don't have the right base path:
Because it nests a second src/ folder in src/. I've tried to add to the sass-loader the sourceMapRoot option:
'sass-loader?sourceMap&sourceMapsRoot=src/'
But it doesn't fix the issue. I know it isn't significant, but I want to know if anyone have it working properly or have the same problem.
Best regards, thank you.

Webpack, sass being overwriten

I'll start by saying I have a bit of a bizarre webpack build. I have 2 projects, the main project and the shared project (like a common library).
Whenever I refer to my shared project from the main project, it get some bizarre IE only/react/webpack build error where I get an error when trying to refer to my shared library. To solve this, I aliased my shared library references to the actual source on my computer in a different folder. That looks something like this:
var alias.shared-library = 'c:\\shared-library\\index.js';
This fixed my bizarre IE problem. However, another issue raised in my webpack production build. On the production server, the shared library exists within the node_modules folder, so I tried something like this:
var alias.shared-library = 'node_modules\\shared-library\\index.js';
It mostly works, except all my scss from the main project is overwritten by scss from the shared project (the output css only contains scss from the shared lib and not main). My full setup looks something like this (I removed parts I thought weren't important):
var SHARED_PATH = path.resolve(__dirname, 'node_modules/shared-library');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractCss = new ExtractTextPlugin('css.styles.css');
const extractScss = new ExtractTextPlugin('scss.styles.css');
const plugs = [];
plugs.push(
new webpack.DefinePlugin({
__DEVELOPMENT__: false
})
);
plugs.push(
new HtmlWebpackPlugin({
template: './index.html',
inject: 'body',
chunks: ['app', 'vendor']
})
);
plugs.push(new webpack.NoErrorsPlugin());
plugs.push(
new CopyWebpackPlugin([
{ from: 'src/assets', to: 'assets' },
])
);
plugs.push(
new SplitByPathPlugin([
{ name: 'vendor', path: [path.join(__dirname, 'node_modules')] },
])
);
plugs.push(extractCss);
plugs.push(extractScss);
plugs.push(
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
})
);
var alias = {
'shared-library': path.resolve(SHARED_PATH, '\\src\\index.js')
};
var loaderDirs = ['node_modules', 'webpack_loaders'];
var moduleDirs = ['node_modules', 'src'];
loaderDirs.push(SHARED_PATH + '\\node_modules');
moduleDirs.push(SHARED_PATH + '\\node_modules');
moduleDirs.push(SHARED_PATH + '\\src');
module.exports = {
entry: {
app: ['./src/index.js']
},
resolve: {
extensions: ['', '.js', '.scss', '.css'],
modulesDirectories: moduleDirs,
alias
},
resolveLoader: {
modulesDirectories: loaderDirs
},
output: {
path: path.join(__dirname, 'dist'),
filename: '[name].[hash].js',
publicPath: '/main/',
sourceMapFilename: '[name].[hash].js.map',
chunkFilename: '[id].chunk.js',
},
plugins: plugs,
module: {
loaders: [
{
test: /\.js?$/,
loader: 'babel?sourceMaps=true',
include: [/src/, path.resolve(SHARED_PATH, '\\src\\index.js')]
},
{
test: /\.css$/,
loader: extractCss.extract('style', 'css')
},
{
test: /\.scss$/,
loader: extractScss.extract('style', 'css!sass'),
include: /src/ // Trying to exclude scss from shared-library, doesn't work though
},
loaders.json,
loaders.image,
loaders.svg,
loaders.font,
loaders.locale,
loaders.html
]
},
postcss: (webpack) => {
return [
autoprefixer({
browsers: ['last 2 versions'],
}),
postcssImport({
addDependencyTo: webpack,
})
];
},
externals: {
'react/lib/ReactContext': 'window',
'react/lib/ExecutionEnvironment': 'window',
'react/addons': true
}
};
I've tried things like different permutations of exclude/include on my loaders. I thought the allChunks option on ExtractTextPlugin might work:
const extractScss = new ExtractTextPlugin({filename: 'scss.styles.css', allChunks: true});
but it just gives me this error:
TypeError: path.replace is not a function
at Template.replacePathVariables (c:\r2\RCA\rca-ui\node_modules\webpack\lib\
TemplatedPathPlugin.js:70:4)
at Template.applyPlugins [as applyPluginsWaterfall] (c:\r2\RCA\rca-ui\node_m
odules\webpack\node_modules\tapable\lib\Tapable.js:37:47)
at Compilation.getPath (c:\r2\RCA\rca-ui\node_modules\webpack\lib\Compilatio
n.js:882:27)
at ExtractTextPlugin.<anonymous> (c:\r2\RCA\rca-ui\node_modules\extract-text
-webpack-plugin\index.js:300:29)
at Array.forEach (native)
at ExtractTextPlugin.<anonymous> (c:\r2\RCA\rca-ui\node_modules\extract-text
-webpack-plugin\index.js:289:20)
at Compilation.next (c:\r2\RCA\rca-ui\node_modules\webpack\node_modules\tapa
ble\lib\Tapable.js:69:14)
at ExtractTextPlugin.<anonymous> (c:\r2\RCA\rca-ui\node_modules\extract-text
-webpack-plugin\index.js:309:4)
at Compilation.applyPluginsAsync (c:\r2\RCA\rca-ui\node_modules\webpack\node
_modules\tapable\lib\Tapable.js:71:13)
at Compilation.<anonymous> (c:\r2\RCA\rca-ui\node_modules\webpack\lib\Compil
ation.js:563:8)
at Compilation.next (c:\r2\RCA\rca-ui\node_modules\webpack\node_modules\tapa
ble\lib\Tapable.js:67:11)
at ExtractTextPlugin.<anonymous> (c:\r2\RCA\rca-ui\node_modules\extract-text
-webpack-plugin\index.js:285:5)
at c:\r2\RCA\rca-ui\node_modules\extract-text-webpack-plugin\node_modules\as
ync\lib\async.js:52:16
at done (c:\r2\RCA\rca-ui\node_modules\extract-text-webpack-plugin\node_modu
les\async\lib\async.js:246:17)
at c:\r2\RCA\rca-ui\node_modules\extract-text-webpack-plugin\node_modules\as
ync\lib\async.js:44:16
at c:\r2\RCA\rca-ui\node_modules\extract-text-webpack-plugin\index.js:269:6
at c:\r2\RCA\rca-ui\node_modules\extract-text-webpack-plugin\node_modules\as
ync\lib\async.js:52:16
at done (c:\r2\RCA\rca-ui\node_modules\extract-text-webpack-plugin\node_modu
les\async\lib\async.js:246:17)
at c:\r2\RCA\rca-ui\node_modules\extract-text-webpack-plugin\node_modules\as
ync\lib\async.js:44:16
at c:\r2\RCA\rca-ui\node_modules\extract-text-webpack-plugin\index.js:259:9
at c:\r2\RCA\rca-ui\node_modules\webpack\lib\Compilation.js:469:4
at Array.forEach (native)
at callback (c:\r2\RCA\rca-ui\node_modules\webpack\lib\Compilation.js:468:14
)
at Compilation.<anonymous> (c:\r2\RCA\rca-ui\node_modules\webpack\lib\Compil
ation.js:489:4)
at c:\r2\RCA\rca-ui\node_modules\webpack\lib\Compilation.js:332:10
at c:\r2\RCA\rca-ui\node_modules\webpack\node_modules\async\lib\async.js:52:
16
at Object.async.forEachOf.async.eachOf (c:\r2\RCA\rca-ui\node_modules\webpac
k\node_modules\async\lib\async.js:236:30)
at Object.async.forEach.async.each (c:\r2\RCA\rca-ui\node_modules\webpack\no
de_modules\async\lib\async.js:209:22)
at Compilation.addModuleDependencies (c:\r2\RCA\rca-ui\node_modules\webpack\
lib\Compilation.js:185:8)
at Compilation.processModuleDependencies (c:\r2\RCA\rca-ui\node_modules\webp
ack\lib\Compilation.js:170:7)
Any ideas on the proper approach to solve this problem? Would the allChunks option help me here? Do I need to tighten up my include/excludes? Is there something else I'm missing? Should I give up and try and fix the IE problem another way? Is there a way I can debug what is happening? Here's the versions of the libraries I am using:
"extract-text-webpack-plugin": "1.0.1",
"style-loader": "0.13.0",
"sass-loader": "3.1.2",
"webpack": "1.13.2"
Thanks

Element from loaders list should have 'loader' or 'loaders' with sass-loader webpack

I have this loader in my webpack loader array:
{ test: /\.scss$/, exclude: /node_modules/, loaders: ExtractTextPlugin('style-loader', 'css-loader!sass-loader') }
I am trying to have webpack build my SCSS to CSS but I am getting this error:
/Users/bli1/Development/Django/CL/cherngloong/cherngloong/cherngloong/node_modules/webpack/node_modules/webpack-core/lib/LoadersList.js:60
throw new Error("Element from loaders list should have one of the fields 'loader' or 'loaders'");
^
Error: Element from loaders list should have one of the fields 'loader' or 'loaders'
at getLoadersFromObject (/Users/bli1/Development/Django/CL/cherngloong/cherngloong/cherngloong/node_modules/webpack/node_modules/webpack-core/lib/LoadersList.js:60:8)
at LoadersList.<anonymous> (/Users/bli1/Development/Django/CL/cherngloong/cherngloong/cherngloong/node_modules/webpack/node_modules/webpack-core/lib/LoadersList.js:78:12)
at Array.map (native)
at LoadersList.match (/Users/bli1/Development/Django/CL/cherngloong/cherngloong/cherngloong/node_modules/webpack/node_modules/webpack-core/lib/LoadersList.js:70:19)
at NormalModuleFactory.<anonymous> (/Users/bli1/Development/Django/CL/cherngloong/cherngloong/cherngloong/node_modules/webpack/lib/NormalModuleFactory.js:109:65)
at /Users/bli1/Development/Django/CL/cherngloong/cherngloong/cherngloong/node_modules/webpack/node_modules/async/lib/async.js:697:13
at /Users/bli1/Development/Django/CL/cherngloong/cherngloong/cherngloong/node_modules/webpack/node_modules/async/lib/async.js:52:16
at done (/Users/bli1/Development/Django/CL/cherngloong/cherngloong/cherngloong/node_modules/webpack/node_modules/async/lib/async.js:248:21)
at /Users/bli1/Development/Django/CL/cherngloong/cherngloong/cherngloong/node_modules/webpack/node_modules/async/lib/async.js:44:16
at /Users/bli1/Development/Django/CL/cherngloong/cherngloong/cherngloong/node_modules/webpack/node_modules/async/lib/async.js:694:17
Here is my full webpack config:
var path = require('path');
var webpack = require('webpack');
var BundleTracker = require('webpack-bundle-tracker');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: [
'./app/index'
],
output: {
path: path.resolve('./public/bundles/'),
filename: "[name]-[hash].js",
},
plugins: [
new BundleTracker({filename: './webpack-stats.json'}),
],
module: {
loaders: [
{ test: /\.css$/, exclude: /node_modules/, loader: 'style!css' },
{ test: /\.json$/, loader: 'json-loader' },
{ test: /\.jsx$/, loaders: ['react-hot', 'babel-loader'], include: path.join(__dirname, 'app') },
{ test: /\.es6$/, exclude: /node_modules/, loader: 'babel-loader?stage=0&optional=runtime'},
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader?stage=0&optional=runtime'},
{ test: /\.scss$/, exclude: /node_modules/, loaders: ExtractTextPlugin('style-loader', 'css-loader!sass-loader') }
]
},
}
Sokra has provided an example of how to use the ExtractTextPlugin here: https://github.com/webpack/extract-text-webpack-plugin/blob/master/example/webpack.config.js
As you can see, there are some differences between your example and his.
The ExtractTextPlugin constructor is called with new inside the "plugins: [ ]" array
The way the plugin is used in the loaders array is by calling the static method .extract(), rather than simply calling the plugin constructor
The reference in the "loader object" is for the "loader:" property, rather than "loaders:" as you have put (loaders is an option but expects an array)
Hope that helps!

Resources