I'm facing a problem with webpack. My project has the following structure.
Folder structure:
src
js
app.js // For importing app.scss file
vendor.js // For importing vendor.scss file
scss
app.scss // Our custom styles
vendor.scss // Require all vendor styles from node_modules
package.json
postcss.config.js
webpack.config.js
Inside scss folder there are 2 files app.scss & vendor.scss. app.scss file contains all our custom styles, vendor.scss file contains all vendor styles such as bootstrap library styles.
After webpack command:
npm run dev
Webpack import these scss files through JavaScript files and add vendor prefixes via postcss-loader and output on a dist
folder.
But I don't want to add vendor prefixes on vendor.scss file because the vendor library already has vendor prefixes. So is there a way to exclude vendor.scss file from postcss-loader.
Full Code:
src/js/app.js:
import '../scss/app.scss'
src/js/vendor.js:
import '../scss/vendor.scss'
src/scss/app.scss:
// Our custom styles
.app {
display: flex;
}
src/scss/vendor.scss:
// Vendor Styles
.container {
display: flex;
}
#import '~bootstrap/scss/bootstrap';
package.json:
{
"name": "test",
"version": "1.0.0",
"description": "",
"private": true,
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack --mode development --progress true --colors"
},
"author": "",
"license": "MIT",
"dependencies": {
"bootstrap": "^4.2.1"
},
"devDependencies": {
"#babel/core": "^7.2.2",
"#babel/preset-env": "^7.3.1",
"autoprefixer": "^9.4.6",
"babel-loader": "^8.0.5",
"css-loader": "^2.1.0",
"filemanager-webpack-plugin": "^2.0.5",
"mini-css-extract-plugin": "^0.5.0",
"node-sass": "^4.11.0",
"postcss-loader": "^3.0.0",
"sass-loader": "^7.1.0",
"webpack": "^4.29.0",
"webpack-cli": "^3.2.1"
}
}
postcss.config.js:
module.exports={
plugins: [
require('autoprefixer')({
'browsers': [
'>= 1%',
'last 1 major version',
'not dead',
'Chrome >= 45',
'Firefox >= 38',
'Edge >= 12',
'Explorer >= 10',
'iOS >= 9',
'Safari >= 9',
'Android >= 4.4',
'Opera >= 30'
],
cascade: true
})
]
};
webpack.config.js:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FileManagerPlugin = require('filemanager-webpack-plugin');
module.exports = function() {
return ({
entry: {
'vendor': './src/js/vendor.js',
'app': './src/js/app.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[chunkhash].js'
},
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.(sa|sc|c)ss$/,
use: [{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
}, {
loader: 'css-loader',
}, // translates CSS into CommonJS
{
loader: 'postcss-loader',
}, // Add vendor prefixes on build css file
{
loader: 'sass-loader',
} // compiles Sass to CSS
]
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash].css'
}),
// Before Build
new FileManagerPlugin({
onStart: {
delete: [
'dist',
],
}
}),
]
});
};
Zip file.
So you want vendor prefixes don't add on Webpack generated vendor.css file.
Remember Webpack parse loader array on reverse order. You could add exclude property on the object of postcss-loader with the regular expression.
webpack.config.js:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const FileManagerPlugin = require('filemanager-webpack-plugin');
module.exports = function() {
return ({
entry: {
'vendor': './src/js/vendor.js',
'app': './src/js/app.js',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].[chunkhash].js'
},
module: {
rules: [{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env']
}
}
},
{
test: /\.s(c|a)ss$/,
use: {
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},// Take scss file and split into a separate css file
},
{
test: /\.s(c|a)ss$/,
use: {
loader: 'css-loader',
},// Interprets scss #import and url() like import/require()
},
{
test: /\.s(c|a)ss$/,
exclude: [/vendor/],
use: {
loader: 'postcss-loader',
},
}, // PostCSS turns your SCSS file into a JS object & converts that object back to a SCSS file
{
test: /\.s(c|a)ss$/,
use: {
loader: 'sass-loader',
},// look for scss file through sass-loader, compile scss into css code
},
]
},
plugins: [
new MiniCssExtractPlugin({
filename: 'css/[name].[contenthash].css'
}),
// Before Build
new FileManagerPlugin({
onStart: {
delete: [
'dist',
],
}
}),
]
});
};
Related
I was trying to use react-datetime-range-picker and When I import it I started getting error.
I have tried other solution but did not work.
Full Error
javascript modules 6.14 KiB
./src/pages/Campaign/CampaignNew.js 2.39 KiB [built]
./node_modules/react-datetime-range-picker/dist/style.css 3.75 KiB [built] [1 error]
ERROR in ./node_modules/react-datetime-range-picker/dist/style.css 5:0
Module parse failed: Unexpected token (5:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured
to process this file. See https://webpack.js.org/concepts#loaders
| */
|
> .rdt {
| position: relative;
| }
# ./node_modules/react-datetime-range-picker/dist/index.js 27:0-22
# ./src/pages/Campaign/CampaignNew.js 3:0-62
# ./src/App.js 6:0-55 16:46-57
# ./src/index.js 1:0-24
I checked webpack.config.js but it looks correct to me.
I have installed style-loader, css-loader
webpack.config.js
const path = require("path");
const webpack = require("webpack");
require('dotenv').config({path: './.env'});
module.exports = {
entry: "./src/index.js",
output: {
path: path.resolve(__dirname, "./static/app_chat/js"),
filename: "[name].js",
},
module: {
rules: [
{
test: /\.(jsx|js)$/,
exclude: /node_modules/,
use: "babel-loader",
},
{
test: /\.(sass|scss|css)$/,
exclude: /node_modules/,
use: ["style-loader", "css-loader"],
},
],
},
optimization: {
minimize: true,
},
plugins: [
new webpack.DefinePlugin({
'process.env': JSON.stringify(process.env),
}),
],
};
package.json
{
"name": "app_chat",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"dev": "webpack --mode development --watch",
"build": "webpack --mode production"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"#babel/core": "^7.20.12",
"#babel/preset-env": "^7.20.2",
"#babel/preset-react": "^7.18.6",
"axios": "^1.2.4",
"babel-loader": "^9.1.2",
"dotenv": "^16.0.3",
"react": "^18.2.0",
"react-datetime": "^3.2.0",
"react-datetime-range-picker": "^3.0.0",
"react-dom": "^18.2.0",
"react-router-dom": "^6.7.0",
"react-switch": "^7.0.0",
"webpack": "^5.75.0",
"webpack-cli": "^5.0.1"
},
"devDependencies": {
"css-loader": "^6.7.3",
"style-loader": "^3.3.1"
}
}
What should I do to fix this problem ?
Please try the following steps if you want to have setup for development and production: (SCSS)
Install the following packages:
yarn add -D postcss-loader postcss-flexbugs-fixes postcss-preset-env style-loader mini-css-extract-plugin
postcss-normalize resolve-url-loader sass-loader
Update your webpack config as follows:
{
test: /\.s?[ac]ss$/,
//removed (exclude: /node_modules/) to enable using external styles
use: [
{
// style-loader => insert styles in the head of the HTML as style tags or in blob links
// MiniCssExtractPlugin => extract styles to a file
loader: isDevelopment ? 'style-loader' : MiniCssExtractPlugin.loader,
//if source map is set to true from previous loaders => this loader will be true as well
},
{
//Resolves #import statements
loader: 'css-loader',
options: {
// used for debugging the app (to see from which component styles are applied)
sourceMap: isDevelopment,
// Number of loaders applied before CSS loader (which is postcss-loader)
importLoaders: 3,
// the following is used to enable CSS modules
...(isCssModules
? {
modules: {
//exclude external styles from css modules transformation
auto: (resourcePath) => !resourcePath.includes('node_modules'),
mode: (resourcePath) => {
if (/global.scss$/i.test(resourcePath)) {
return 'global';
}
return 'local';
},
localIdentName: isDevelopment ? '[name]_[local]' : '[contenthash:base64]',
localIdentContext: srcPath,
localIdentHashSalt: 'react-boilerplate',
exportLocalsConvention: 'camelCaseOnly',
},
}
: {}),
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
ident: 'postcss',
plugins: [
'postcss-flexbugs-fixes',
postcssPresetEnv({
stage: 3,
//uncomment the following if you want to prefix grid properties
// autoprefixer: { grid: true },
}),
// Adds PostCSS Normalize as the reset css with default options,
// so that it honors browserslist config in package.json
// which in turn let's users customize the target behavior as per their needs.
'postcss-normalize',
],
},
sourceMap: isDevelopment,
},
},
{
//Rewrites relative paths in url() statements based on the original source file
loader: 'resolve-url-loader',
options: {
//needs sourcemaps to resolve urls (images)
sourceMap: true,
},
},
{
//Compiles Sass to CSS
loader: 'sass-loader',
options: {
sourceMap: true,
},
},
],
},
Check out the following repository for reference:
React webpack boilerplate
I have a complete site that I want to design a build tool for it.In fact, I chose Webpack for doing that. The project structure is like this:
I have nunjucks, html, css, sass and js files. I must bundle them via webpack. My webpack config file is here:
var HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const path = require('path')
const CopyPlugin = require('copy-webpack-plugin')
const NunjucksWebpackPlugin = require('nunjucks-webpack-plugin')
module.exports = {
entry: ['./src/index.js'],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
writeToDisk: true
},
plugins: [
new CopyPlugin([
{ from: 'public/images', to: 'images' },
{ from: 'public/fonts', to: 'fonts' },
{ from: 'src/pages/about', to: '.' }
]),
new CleanWebpackPlugin(),
// new HtmlWebpackPlugin()
new HtmlWebpackPlugin({
title: 'Asset Management' //title of file.html
})
],
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
{
test: /\.s[ac]ss$/i,
use: [
// Creates `style` nodes from JS strings
'style-loader',
// Translates CSS into CommonJS
'css-loader',
// Compiles Sass to CSS
'sass-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['file-loader']
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: ['file-loader']
},
{
test: /\.(njk|nunjucks)$/,
loader: 'nunjucks-loader'
},
{
// to auto refresh index.html and other html
test: /\.html$/,
loader: 'raw-loader',
exclude: /node_modules/
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
options: {
interpolate: true
}
}
]
}
]
}
}
The "index.js" file also is like this:
import _ from 'lodash'
import './pages/about/about_moon.scss'
import './pages/about/about_moon.html'
var tpl = require('./pages/home/index_moon.njk')
var html = tpl.render({ message: 'Foo that!' })
function component() {
return element
}
document.body.appendChild(component())
I configured the "package.json" file and defined scripts to run webpack:
"start": "webpack-dev-server --open",
"build": "webpack"
The problem is when I run npm run build, the dist folder was made and it had a html file but there is nothing to show. I have already had some html files and wanted to bundle all of them to "bundle.js", but I have not known how. Would you please tell me how I can bundle this project?
Thank you in advance.
Problem solved. I changed the Webpack.config.js file to this:
const path = require('path')
var HtmlWebpackPlugin = require('html-webpack-plugin')
var UglifyJSPlugin = require('uglifyjs-webpack-plugin')
const CopyPlugin = require('copy-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const BrowserSyncPlugin = require('browser-sync-webpack-plugin')
module.exports = {
entry: ['./src/index.js', './script.js'],
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
// HtmlWebpackPluginConfig
new HtmlWebpackPlugin({
filename: 'index.html',
inject: 'head',
template: './index.njk'
}),
new CleanWebpackPlugin(),
new CopyPlugin([
{ from: 'public/images', to: 'images' },
{ from: 'public/fonts', to: 'fonts' }
])
],
module: {
rules: [
{
test: /\.exec\.js$/,
use: ['script-loader']
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.(scss)$/,
use: [
{
// Adds CSS to the DOM by injecting a `<style>` tag
loader: 'style-loader'
},
{
// Interprets `#import` and `url()` like `import/require()` and will resolve them
loader: 'css-loader'
},
{
// Loader for webpack to process CSS with PostCSS
loader: 'postcss-loader',
options: {
plugins: function() {
return [require('autoprefixer')]
}
}
},
{
// Loads a SASS/SCSS file and compiles it to CSS
loader: 'sass-loader'
}
]
},
{
// HTML LOADER
// Super important: We need to test for the html
// as well as the nunjucks files
test: /\.html$|njk|nunjucks/,
use: [
'html-loader',
{
loader: 'nunjucks-html-loader',
options: {
// Other super important. This will be the base
// directory in which webpack is going to find
// the layout and any other file index.njk is calling.
// searchPaths: [...returnEntries('./src/pages/**/')]
// Use the one below if you want to use a single path.
// searchPaths: ['./']
}
}
]
}
]
}
}
Also, I wrote the script.js file like this, since, function names were changed and they could not be run after bundling.
document.getElementById('body').onload = function() {
console.log('Document loaded')
var menu = localStorage.getItem('menu')
if (menu === 'opened')
document.getElementById('navigation').classList.add('opened')
}
document.getElementById('menu-button').onclick = function() {
// localstorage used to define global variable
var menu = localStorage.getItem('menu')
localStorage.setItem('menu', menu === 'closed' ? 'opened' : 'closed')
document.getElementById('navigation').classList.toggle('opened')
}
// Window.onLoad = onLoad // global variable in js
The index.js was used to import other files and it was like this:
import _ from 'lodash'
require('../index.njk')
require('../base.html')
require('../style.css')
This is the Json file:
{
"name": "menu_moon",
"version": "1.0.0",
"description": "",
"private": true,
"dependencies": {
"browser-sync": "^2.26.7",
"extract-text-webpack-plugin": "^3.0.2",
"fast-glob": "^3.1.1",
"fs-extra": "^8.1.0",
"g": "^2.0.1",
"html-loader": "^0.5.5",
"i": "^0.3.6",
"lodash": "^4.17.15",
"mkdirp": "^0.5.1",
"nunjucks": "^3.2.0",
"nunjucks-html-loader": "^1.1.0",
"nunjucks-isomorphic-loader": "^2.0.2",
"nunjucks-loader": "^3.0.0",
"raw-loader": "^4.0.0"
},
"devDependencies": {
"browser-sync-webpack-plugin": "^2.2.2",
"clean-webpack-plugin": "^3.0.0",
"copy-webpack-plugin": "^5.0.5",
"css-loader": "^3.2.1",
"file-loader": "^5.0.2",
"html-webpack-plugin": "^3.2.0",
"node-sass": "^4.13.0",
"nunjucks-webpack-plugin": "^5.0.0",
"sass-loader": "^8.0.0",
"script-loader": "^0.7.2",
"style-loader": "^1.0.1",
"uglifyjs-webpack-plugin": "^2.2.0",
"webpack": "^4.41.2",
"webpack-cli": "^3.3.10",
"webpack-dev-server": "^3.9.0"
},
"scripts": {
"moon-start": "browser-sync start --server --files './**/*.*'",
"moon-build": "node build_product_moon.js",
"start": "webpack-dev-server --open",
"build": "webpack"
},
"author": "",
"license": "ISC"
}
I hope it was useful for others.
I am trying my hands on Webpack4/Redux/React and getting the following error for my sample application:
./src/index.js] 210 bytes {main} [built] [failed] [1 error]
+ 13 hidden modules
ERROR in ./src/index.js Module parse failed: Unexpected token (3:16)
You may need an appropriate loader to handle this file type. | import
React from 'react'; | | const element = Hello, world; | | #
multi webpack-dev-server/client?http://localhost:3000
webpack/hot/only-dev-server ./src/index i 「wdm」: Failed to compile.
I have tried different ways to resolve this (as is evident from commented out code) without any success. Please let me know what I am missing. My Code files are as follows:
Package.json:
{
"name": "react-redux-example",
"version": "1.0.0",
"description": "using redux architecture",
"main": "node server.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"repository": {
"type": "git",
"url": "git"
},
"keywords": [
"reactjs",
"redux",
"react",
"hot",
"reload",
"live",
"edit",
"webpack"
],
"author": "newbieToReact",
"license": "MIT",
"dependencies": {
"babel": "^6.23.0",
"mkdirp": "^0.5.1",
"react": "^16.4.0",
"react-router": "^4.2.0",
"style-loader": "^0.21.0",
"webpack": "^4.10.2",
"webpack-dev-server": "^3.1.4"
},
"devDependencies": {
"extract-text-webpack-plugin": "^4.0.0-beta.0"
}
}
webpack.config.js
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var devFlagPlugin = new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.DEBUG || 'true'))
});
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./src/index'
],
mode: "development",
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
//new webpack.NoErrorsPlugin(),
new webpack.NoEmitOnErrorsPlugin(),
devFlagPlugin,
new ExtractTextPlugin('app.css')
],
// module: {
// loaders: [
// {
// test: /\.jsx?$/,
// loaders: ['react-hot', 'babel'],
// include: path.join(__dirname, 'src')
// },
// { test: /\.css$/, loader: ExtractTextPlugin.extract('css-loader?module!cssnext-loader') }
// ]
// },
//module: {
// rules: [
// {
// exclude: '/node_modules/',
//test: /\.jsx?$/,
//test: /\.js$/,
// test: /\.(js|jsx)$/,
// include: path.join(__dirname, 'src'),
// test: /\.css$/,
// use: [
// { loader: "react-hot" },
// { loader: "babel" },
// { loader: "ExtractTextPlugin.extract('css-loader?module!cssnext-loader')"},
// { loader: "style-loader" },
// ]
// }
// ]
// },
module: {
rules: [
{
exclude: '/node_modules/',
test: /\.(js|jsx)$/,
include: path.join(__dirname, 'src'),
test: /\.css$/,
loader: "react-hot",
loader: "babel",
loader: "ExtractTextPlugin.extract('css-loader?module!cssnext-loader')",
loader: "style-loader",
}
]
},
resolve: {
extensions: ['.js', '.json']
}
};
src/index.js
import React from 'react';
const element = <h1>Hello, world</h1>;
Your module/loaders needs another clause in test: this needs to be test: /\.(js|jsx)$/, because you are using a .js file and no .jsx. Also it's a good practice to include this in your config: resolve: { extensions: ['.js'] }, when using .js instead off .jsx. Also uncomment the second loader because i see you're using a .css this needs the css-loader to work.
You will have to add css-loader and babel-loader to your devDependencies aswell.
Also you're using webpack 4 which implies that ExtractTextPlugin has been deprecated so remove this.
Hope this helped, good luck!
In webpack.config.js you should follow scheme described in webpack docs
Here is an example
rules: [{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
}, {
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
}]
After webpack command webpack catch all files and finish build in dist folder, but react component doesn't work. I don't understand why. My configs attached:
package.json
{
"name": "name",
"version": "1.0.0",
"description": "Example",
"main": "index.js",
"scripts": {
"watch": "webpack --progress --watch",
"start": "webpack-dev-server --open",
"build": "webpack"
},
"devDependencies": {
"autoprefixer": "^7.1.3",
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"clean-webpack-plugin": "^0.1.16",
"css-loader": "^0.28.7",
"extract-text-webpack-plugin": "^3.0.0",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.30.1",
"node-sass": "^4.5.3",
"optimize-css-assets-webpack-plugin": "^3.1.1",
"postcss-loader": "^2.0.6",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"sass-loader": "^6.0.6",
"style-loader": "^0.18.2",
"webpack": "^3.5.5",
"webpack-dev-server": "^2.7.1"
},
"browserslist": [
"last 15 versions",
"> 1%",
"ie 8",
"ie 7"
]
}
webpack.config.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
const OptimizeCssAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: ['./app/app.js', './app/sass/app.sass'
],
output: {
filename: 'app.js',
path: path.resolve(__dirname, 'dist')
},
devServer: {
contentBase: './dist'
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader'
}
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: ["css-loader", "postcss-loader"]
}),
},
{
test: /\.(sass|scss)$/,
use: ExtractTextPlugin.extract(['css-loader', 'postcss-loader', 'sass-loader'])
},
{
test: /\.(png|svg|jpg|gif)$/,
use: {
loader: 'file-loader',
options: {
name: 'img/[name].[ext]', // check the path
}
},
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
use: {
loader: 'file-loader',
options: {
name: 'fonts/[name].[ext]', // check the path
}
}
}
]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Build version'
}),
new ExtractTextPlugin({
filename: 'css/app.min.css',
allChunks: true,
}),
new OptimizeCssAssetsPlugin()
]};
babel.rc
{"presets":["es2015", "react"]}
app file system:
app/
components/
fonts/
img/
sass/
app.js
index.html
index.html has a <div> with id="app" and script with src="app.js" in the body.
Move react and react-dom to dependencies instead of devDependecies in your package.json then try to build again.
Check this answer for an explanation:
Bower and devDependencies vs dependencies
Your react and react-dom packages are dependencies try moving them there.
Try modifying your webpack config file to some like this:
module.exports = {
entry: [
'./app/app.js',
],
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js',
publicPath: '/dist',
sourceMapFilename: 'bundle.map',
},
devtool: process.env.NODE_ENV === 'production' ? undefined : 'cheap-module-eval-source-map',
resolve: {
modules: ['node_modules', './app/components'],
extensions: ['.js', '.jsx'],
},
module: {
loaders: [
{
test: /(\.js$|\.jsx$)/,
exclude: /(node_modules|bower_components)/,
use: [
{
loader: 'babel-loader',
options: {
presets: ['react', 'es2015'],
},
},
],
},
{
test: /\.scss$/,
use: ['style-loader', 'css-loader', 'sass-loader'],
},
],
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
minimize: true,
compressor: {
warnings: false,
},
})
],
};
Add other necessary rules you need to the rules array.
With this config though, you don't need the .babelrc file as everything is all in place.
I'm a total newcomer to Webpack (2) so please forgive me for my simple understanding so far.
Following from a few tutorials around the web, I've cobbled together a working package.json and webpack.babel.config.js file.
Essentially, I am trying to turn SCSS into CSS, Pug into HTML and JS into Babel'd JS.
When I run my dist command, it produces the files, but also along with it, are .js files for each .scss and .html etc. Hopefully the image below can illustrate this:
Ideally what I'm after is simply, app.css, index.html and app.js.
webpack.babel.config.js
import webpack from 'webpack';
import path from 'path';
import autoprefixer from 'autoprefixer';
import ExtractTextPlugin from 'extract-text-webpack-plugin';
import HtmlWebpackPlugin from 'html-webpack-plugin';
const extractHtml = new ExtractTextPlugin({
filename: '[name].html'
});
const extractPug = new ExtractTextPlugin({
filename: '[name].[contenthash].pug'
});
const extractScss = new ExtractTextPlugin({
filename: '[name].[contenthash].css',
allChunks: true
});
let config = {
stats: {
assets: false,
colors: true,
version: false,
hash: true,
timings: true,
chunks: false,
chunkModules: false
},
entry: {
'dist/html/app': [
path.resolve(__dirname, 'src/pug/app.pug')
],
'dist/js/app': [
path.resolve(__dirname, 'src/js/app.js')
],
'dist/css/app': [
path.resolve(__dirname, 'src/scss/app.scss')
]
},
output: {
path: path.resolve(__dirname, './'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.pug$/,
use: extractHtml.extract({
use: ['html-loader','pug-html-loader?pretty=false&exports=false']
})
},
{
test: /\.js$/,
exclude: /(node_modules|bower_components)/,
use: ['babel-loader']
},
{
test: /\.scss$/,
use: extractScss.extract({
use: ['css-loader', 'postcss-loader', 'sass-loader']
})
}
]
},
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: false,
stats: 'errors-only',
open: false
},
plugins: [
new HtmlWebpackPlugin({
title: 'Portfolio',
// minify: {
// collapseWhitespace: true
// },
hash: true,
template: './dist/html/app.html',
filename: 'index.html'
}),
new webpack.LoaderOptionsPlugin({
minimize: false,
debug: true,
options: {
babelLoader: {
presets: [
['es2015']
]
},
postcss: [
autoprefixer({
browsers: ['last 2 versions', 'Explorer >= 9', 'Android >= 4']
})
],
sassLoader: {
includePaths: [
path.resolve(__dirname, 'node_modules/sanitize.css/')
]
}
}
}),
extractScss,
extractHtml,
extractPug
]
}
export default config;
package.json
{
"name": "portfolio",
"version": "1.0.0",
"description": "Portfolio of Michael Pumo",
"main": "index.js",
"scripts": {
"dev": "webpack-dev-server",
"prod": "webpack -p",
"dist": "webpack --config webpack.config.babel.js"
},
"author": "Michael Pumo",
"license": "ISC",
"devDependencies": {
"autoprefixer": "^6.7.7",
"babel-core": "^6.24.0",
"babel-loader": "^6.4.1",
"babel-preset-es2015": "^6.24.0",
"css-loader": "^0.27.3",
"extract-text-webpack-plugin": "^2.1.0",
"html-loader": "^0.4.5",
"html-webpack-plugin": "^2.28.0",
"html-webpack-pug-plugin": "^0.0.3",
"node-sass": "^4.5.0",
"postcss-loader": "^1.3.3",
"pug": "^2.0.0-beta11",
"pug-html-loader": "1.1.1",
"sass-loader": "^6.0.3",
"style-loader": "^0.14.1",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.4.2"
}
}
I have many other issues I'd like to resolve too but I'm taking it one issue at a time. Thanks for your help.
You don't want to use multiple entries, but instead add it to a single entry. For it to work nicely with the extract-text-webpack-plugin you should also change the output a little. It makes it much easier when you set output.path to the dist/ directory, which also makes more sense conceptually. You'll have one entry point for app and then you set the output for the different file types to the corresponding directories. For JavaScript that's the output.filename option, which you want in js/. Your entry and output should look likes this:
entry: {
app: [
path.resolve(__dirname, 'src/pug/app.pug'),
path.resolve(__dirname, 'src/js/app.js'),
path.resolve(__dirname, 'src/scss/app.scss')
]
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/[name].js'
},
And you do the same thing as with output.filename for the filename in the extract text plugins:
const extractHtml = new ExtractTextPlugin({
filename: 'html/[name].html'
});
const extractScss = new ExtractTextPlugin({
filename: 'css/[name].[contenthash].css',
allChunks: true
});
You didn't use extractPug at all, so I left it off and you probably want to remove it.
The output will look likes this:
dist
├─ css
│ └─ app.50352154102b272d39e16c28ef00c1ac.css
├─ html
│ └─ app.html
├─ js
│ └─ app.js
└─ index.html
Now you also have index.html in the dist directory and you can simply deploy the dist directory, as it's self-contained.
On a side note: You should not use ./dist/html/app.html as a template to html-webpack-plugin but instead use the .pug file directly with the pug-loader, which means that you don't even need to add it to the entry or extract the HTML.
From what I understand, there is one output for each of your entry points (this seems to suggest that way). I believe the most common use case is that there is only one entry point (usually app.js or index.js), and all the required files (like css and other js files) are "required" in the app.js (or import if you are using ES6). That way, there is just one output js file. Also, you can define where to store the individual output files for each loader in the loader's query.
For example, this is a part of my webpack config file:
module: {
loaders: [
{test: /\.css$/, loader: 'style-loader!css-loader' },
{test: /\.js$/, exclude: /node_modules/, loaders: ['babel-loader']},
{test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/, loader: 'file-loader', query: {name: 'fonts/[name].[ext]'}},
{test: /\.(jpg|png)$/, loader: 'file-loader', query: {name: 'img/[name].[ext]'}},
{test: /\.ico$/, loader: 'file-loader?name=[name].[ext]'}
]
}
The query parameter on each loader is specifying the output directory and filename for each of the loaders.