I have the following folder structure (here is the demo app source code):
MyComp.scss:(app\web\src\components\MyComp\MyComp.scss)
I've below URL:
.content{
background-image: url(/icons/myIcon.png); // should resolve to web\icons\myIcon.png
}
Webpack is throwing error for this:
Error: Can't resolve '/icons/myIcon.png' in
'C:\app\web\src\components\
MyContainer.jsx: (app\web\src\containers\MyContainer\MyContainer.jsx) I am using below absolute imports which are giving errors:
import MyComp from 'components/MyComp'; // This should resolve to app\web\src\components\MyComp\MyComp.jsx
import { authorizingUser } from 'myRedux'; // should resolve to app\unify\myRedux\modules\auth\actions.js
Moreover, node_modules imports are also failing:
ERROR in ./node_modules/node-fetch/index.js 10:11-26 Module not found:
Error: Can't resolve 'http' in 'C:\node_modules\node-fetch'
Here is how my webpack config is:
config.js: (app\web\build\config.js)
const path = require('path');
const root = path.resolve(__dirname, '..', '..', '..'); // Project root.
const webRoot = path.resolve(root, 'app', 'web');
const assetPath = path.resolve(root, 'web', 'dist');
module.exports = { root, webRoot, assetPath };
webpack.frontend.config: (app\web\build\webpack.frontend.config.js)
require('dotenv').config();
const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const AssetsPlugin = require('assets-webpack-plugin');
const config = require('./config.js');
const PROD = process.env.NODE_ENV === 'production';
const cssLoader = (enableModules = true) => {
return {
loader: 'css-loader',
options: {
modules: enableModules,
sourceMap: !PROD,
importLoaders: 2,
modules: {
localIdentName: PROD ? '[local]__[hash:base64:5]' : '[local]',
},
},
};
};
const postCssLoader = {
loader: 'postcss-loader',
options: {
sourceMap: !PROD,
postcssOptions: {
public: [
'postcss-preset-env',
{
// Options
browsers: 'last 2 versions',
},
],
},
},
};
const sassLoader = {
loader: 'sass-loader',
options: {
sourceMap: !PROD,
},
};
const localStyleLoaders = [cssLoader(), postCssLoader, sassLoader];
// We want to disable css module.
const globalStyleLoaders = [cssLoader(false), postCssLoader, sassLoader];
const devPlugins = [new webpack.HotModuleReplacementPlugin()]; // <- To generate hot update chunk
const prodPlugins = [];
const devEntries = [
`webpack-dev-server/client?path=https://my-domain.com:443`, // <-- Enables web socket connection (needs url & port)
'webpack/hot/dev-server', // <- To perform HMR in the browser
];
const clientAppEntryFilePath = path.resolve(config.webRoot, 'src/client.jsx');
module.exports = {
entry: {
frontEndMain: [
'babel-polyfill',
...(PROD ? [] : devEntries),
clientAppEntryFilePath,
],
},
output: {
path: config.assetPath,
filename: '[name]-[hash].js', // Hash is used to force cache invalidation.
publicPath: PROD
? '/dist'
: `https://my-domain.com:443/dist/`,
},
module: {
rules: [
//JavaScript & JSX
{
test: /\.(jsx|js)$/,
exclude: /node_modules/,
use: ['babel-loader'],
},
// For local styles.
{
test: /\.(scss|css)$/,
use: PROD
? [MiniCssExtractPlugin.loader, ...localStyleLoaders]
: ['style-loader', ...localStyleLoaders],
include: path.resolve(config.webRoot, 'src'),
exclude: path.resolve(config.webRoot, 'src', 'theme'),
},
// Global styles
// Just like the normal style loader stack, but without css modules so we don't modify
// classnames for our style libraries like bootstrap, slick, etc
{
test: /\.(scss|css)$/,
use: PROD
? [MiniCssExtractPlugin.loader, ...globalStyleLoaders]
: ['style-loader', ...globalStyleLoaders],
include: [path.resolve(config.webRoot, 'src', 'theme'), /node_modules/],
},
// Images: Copy image files to build folder
{
test: /\.(?:ico|gif|png|jpg|jpeg)$/i,
loader: 'url-loader',
options: {
limit: 10240,
},
},
{
test: /\.woff2?(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/font-woff',
},
},
{
test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'application/octet-stream',
},
},
{
test: /\.svg(\?v=\d+\.\d+\.\d+)?$/,
loader: 'url-loader',
options: {
limit: 10000,
mimetype: 'mimetype=image/svg+xml',
},
},
{
test: /\.eot(\?v=\d+\.\d+\.\d+)?$/,
loader: 'file-loader',
},
],
},
resolve: {
modules: [
'node_modules',
// Since I am using absolute import for custom modules/js. So this is required.
'app',
'app/unify',
'app/web/src',
],
extensions: ['.js', '.jsx'],
},
plugins: [
...(PROD ? prodPlugins : devPlugins),
new CleanWebpackPlugin(),
// Since I have hashed frontEnd js/css, so this generates assets info file on root and
// which has assets info.
new AssetsPlugin({
path: config.root,
filename: 'web-frontend-assets.json',
prettyPrint: true,
}),
new webpack.DefinePlugin({
// To resolve this error on production build.
// "You are currently using minified code outside of NODE_ENV === 'production'"
'process.env': {
NODE_ENV: JSON.stringify(PROD ? 'production' : 'development'),
PLATFORM: JSON.stringify(process.env.PLATFORM),
WEB_ENV: JSON.stringify(process.env.WEB_ENV),
},
__CLIENT__: true,
__SERVER__: false,
__DEVELOPMENT__: process.env.NODE_ENV !== 'production',
}),
],
devServer: {
https: {
key: fs.readFileSync(`${config.webRoot}/certs/key.pem`),
cert: fs.readFileSync(`${config.webRoot}/certs/cert.pem`),
},
host: 'my-domain.com',
port: '443',
quiet: true,
inline: true,
hot: true,
compress: true, // <- Enables HMR in webpack-dev-server and in libs running in the browser
historyApiFallback: true,
disableHostCheck: true,
clientLogLevel: 'silent',
publicPath: `https://my-domain.com:443/dist/`,
contentBase: `https://my-domain.com:443`,
headers: { 'Access-Control-Allow-Origin': '*' },
stats: { colors: true },
},
node: false,
stats: {
preset: 'detailed',
assets: true,
builtAt: true,
moduleAssets: false,
assetsSpace: 15,
modulesSpace: 15,
colors: true,
env: true,
errors: true,
errorDetails: true,
errorStack: true,
reasons: true,
modules: true,
},
};
package.json:
"scripts": {
"start-frontend": "webpack --config ./app/web/build/webpack.frontend.config.js"
},
I am not sure, what exactly I need to pass in entry.frontEndMain, output.publicPath, devServer.publicPath, devServer.contentBase
Related
I have a vue 3 app where I set up webpack 5 eventually. As I see I eliminated all my issues now the only thing remains is that it does not load my svg-s and images when I run the webpack serve script in dev mode. How can I configure webpack so that it would bundle my svg-s from the scr/assets folder?
my webpack config:
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader');
const env = process.env.NODE_ENV || 'development';
const mode = process.env.VUE_APP_MODE || 'not-fullstack';
module.exports = {
mode: 'development',
entry: './src/main.js',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
alias: {
vue: '#vue/runtime-dom',
'#': path.join(__dirname, 'src'),
},
fallback: { crypto: false, stream: false },
},
module: {
rules: [
{
test: /\.vue$/,
use: [
{
loader: 'vue-loader',
},
],
},
{
test: /\.css$/i,
use: ['style-loader', 'css-loader', 'postcss-loader'],
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: 'images/[name].[hash].[ext]',
},
type: 'asset/resource',
},
{
test: /\.svg$/i,
use: [
{
loader: 'url-loader',
options: {
encoding: false,
},
},
],
},
],
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, './public/index.html'),
}),
new VueLoaderPlugin(),
new CopyPlugin([
{ noErrorOnMissing: true, from: './src/assets', to: 'images' },
]),
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(env),
'process.env.VUE_APP_MODE': JSON.stringify(mode),
}),
],
devServer: {
historyApiFallback: true,
compress: true,
port: 3000,
},
};
And I reference my svg-s in my Vue component like this:
<img src="../../assets/logo.svg" alt="logo" />
As you can see I tried with the copy-webpack-plugin, maybe I just configured it wrong.
Thank you for your help in advance!
The config in webpack5 changed a lot
{
loader: 'url-loader',
options: {
encoding: false,
},
This is not working anymore. The url-loader is even removed from the npm packages.
The current way is found in the documentation
https://webpack.js.org/guides/asset-management/#loading-images
I recently upgraded to webpack#5.44 and after that my build for dev is giving proper bundle names but when I run the build in production mode it gives numeric bundle names.
And some of the bundle get lost in the production build.
webpack.dev.config.js (for dev build)
const webpack = require('webpack')
const path = require('path')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const BrotliPlugin = require('brotli-webpack-plugin')
const CompressionPlugin = require('compression-webpack-plugin')
const ACCEPTABLE_GOV_CLOUD_STRINGS = ['gov', 'govcloud']
module.exports = function(env = {}, argv) {
const mode = argv.mode
const cloudMode = argv.cloudmode || ''
require('dotenv').config({path: `./.env.${mode}`})
const envVariables = process.env
const {
APOLLO_URL,
APOLLO_VERSION,
WEBSOCKET_URL,
SETTINGS_URL,
PREPROD_SETTINGS_URL,
AUTH_URL,
PREPROD_AUTH_URL,
EDR_URL,
MFS_MEDIATOR,
CSA_DASHBOARD_URL,
PREPROD_CSA_DASHBOARD_URL,
} = envVariables
const basePath = argv['ui-version'] ? `/ui-${argv['ui-version']}/` : '/ui-v5/'
// eslint-disable-next-line no-console
console.log('Building for ' + mode + '...', argv.iam)
const config = {
entry: path.resolve(__dirname, 'src/index.tsx'),
output: {
publicPath: basePath,
filename: '[name].[fullhash].js',
chunkFilename: '[name].[fullhash].js',
path: path.join(__dirname, './build'),
},
mode: mode,
devtool: 'eval-source-map',
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json', '.jsx'],
fallback: {
fs: false,
tls: false,
net: false,
path: false,
zlib: false,
http: false,
https: false,
stream: false,
crypto: require.resolve('crypto-browserify'),
},
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: [/node_modules/],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
},
{
test: /\.m?js/,
resolve: {
fullySpecified: false,
},
},
{
test: /\.js?$/,
exclude: [/node_modules/],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
},
{
test: /\.(svg|png|jpg|woff|woff2|eot|ttf|otf)$/,
use: 'file-loader',
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'index.html'),
SETTINGS_URL:
argv.iam === 'preprod' ? PREPROD_SETTINGS_URL : SETTINGS_URL,
AUTH_URL: argv.iam === 'preprod' ? PREPROD_AUTH_URL : AUTH_URL,
MFS_MEDIATOR: `${basePath}${MFS_MEDIATOR}`,
}),
new ForkTsCheckerWebpackPlugin({memoryLimit: 5000}),
new webpack.HotModuleReplacementPlugin(),
new webpack.EnvironmentPlugin({
NODE_ENV: mode, // default value matches mode
APOLLO_ACCESS_TOKEN: null, // default value of null => unset
APOLLO_ACCESS_TOKEN_EXPIRES: null, // default value of null => unset
APOLLO_URL: APOLLO_URL, //envConfig[envMode].APOLLO_URL,
APOLLO_VERSION: APOLLO_VERSION,
WEBSOCKET_URL: WEBSOCKET_URL,
EDR_URL: EDR_URL,
IS_GOV_CLOUD: ACCEPTABLE_GOV_CLOUD_STRINGS.includes(
cloudMode.toLowerCase(),
),
CSA_DASHBOARD:
argv.iam === 'preprod'
? PREPROD_CSA_DASHBOARD_URL
: CSA_DASHBOARD_URL,
basePath: basePath,
}),
new CompressionPlugin(),
new BrotliPlugin({
asset: '[path].br[query]',
test: /\.(js|css|html|svg|woff|woff2)$/,
}),
],
devServer: {
host: '0.0.0.0',
port: 7676,
historyApiFallback: {
index: basePath,
},
https: true,
},
optimization: {
splitChunks: {
chunks: 'all',
},
moduleIds: 'named',
},
}
return config
}
webpack.config.js (for production build)
const webpack = require('webpack')
const path = require('path')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const BrotliPlugin = require('brotli-webpack-plugin')
const CompressionPlugin = require('compression-webpack-plugin')
const ACCEPTABLE_GOV_CLOUD_STRINGS = ['gov', 'govcloud']
module.exports = function(env = {}, argv) {
const mode = argv.mode === 'none' ? 'staging' : argv.mode
const cloudMode = argv.cloudmode || ''
require('dotenv').config({path: `./.env.${mode}`})
const envVariables = process.env
const {
APOLLO_URL,
APOLLO_VERSION,
WEBSOCKET_URL,
SETTINGS_URL,
PREPROD_SETTINGS_URL,
AUTH_URL,
PREPROD_AUTH_URL,
EDR_URL,
MFS_MEDIATOR,
CSA_DASHBOARD_URL,
PREPROD_CSA_DASHBOARD_URL,
} = envVariables
const basePath = argv['ui-version'] ? `/ui-${argv['ui-version']}/` : '/ui-v5/'
// eslint-disable-next-line no-console
console.log(`Building for ${mode} ...`)
const config = {
entry: path.resolve(__dirname, 'src/index.tsx'),
output: {
publicPath: basePath,
filename: '[name].[fullhash].js',
chunkFilename: '[name].[fullhash].js',
path: path.join(__dirname, './build'),
},
mode: 'production',
// NOTE:
// For production builds devtool should either be not present or 'source-map'.
// Please do not set any other value that will bundle the sourcemap into the prod bundle.js
devtool: mode === 'production' ? false : 'eval-source-map',
resolve: {
extensions: ['.ts', '.tsx', '.js', '.json', '.jsx'],
fallback: {
"fs": false,
"tls": false,
"net": false,
"path": false,
"zlib": false,
"http": false,
"https": false,
"stream": false,
"crypto": require.resolve('crypto-browserify'),
}
},
module: {
rules: [
{
test: /\.tsx?$/,
exclude: [/node_modules/],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
},
{
test: /\.js?$/,
exclude: [/node_modules/],
use: {
loader: 'babel-loader',
options: {
cacheDirectory: true,
},
},
},
{
test: /\.m?js/,
resolve: {
fullySpecified: false
}
},
{
test: /\.(svg|png|jpg|woff|woff2|eot|ttf|otf)$/,
use: 'file-loader',
},
{
test: /\.css$/,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new HtmlWebpackPlugin({
template: path.resolve(__dirname, 'index.html'),
SETTINGS_URL:
argv.iam === 'preprod' ? PREPROD_SETTINGS_URL : SETTINGS_URL,
AUTH_URL: argv.iam === 'preprod' ? PREPROD_AUTH_URL : AUTH_URL,
MFS_MEDIATOR: `${basePath}${MFS_MEDIATOR}`,
}),
new ForkTsCheckerWebpackPlugin({ memoryLimit: 5000 }),
new webpack.HotModuleReplacementPlugin(),
new webpack.EnvironmentPlugin({
NODE_ENV: 'production', // default value matches mode
APOLLO_ACCESS_TOKEN: null, // default value of null => unset
APOLLO_ACCESS_TOKEN_EXPIRES: null, // default value of null => unset
APOLLO_URL: APOLLO_URL,
APOLLO_VERSION: APOLLO_VERSION,
WEBSOCKET_URL: WEBSOCKET_URL,
EDR_URL: EDR_URL,
IS_GOV_CLOUD: ACCEPTABLE_GOV_CLOUD_STRINGS.includes(
cloudMode.toLowerCase(),
),
CSA_DASHBOARD:
argv.iam === 'preprod'
? PREPROD_CSA_DASHBOARD_URL
: CSA_DASHBOARD_URL,
basePath: basePath,
}),
new CompressionPlugin(),
new BrotliPlugin({
asset: '[path].br[query]',
test: /\.(js|css|html|svg|woff|woff2)$/,
}),
],
devServer: {
host: '0.0.0.0',
port: 7676,
historyApiFallback: {
index: basePath,
},
https: true,
},
optimization: {
splitChunks: {
chunks: 'all',
},
moduleIds: 'named',
},
}
return config
}
What can I do to resolve this?
According to the docs, it looks like setting mode to production "Enables deterministic mangled names for modules and chunks". You also have optimization.moduleIds set to "named". According to the optimization documentation, that value creates readable ids for debugging.
My guess is these two settings are clashing. You may want your production configuration to have "deterministic" for your optimization.moduleIds setting.
The Webpack Bulid runs pretty slow, project background is a community portal developed in Vue.js...
Can anybody tell if there is any potential for improvement and if so, what?
I wonder if the time for the build process of 37401ms can still be changed by changing the codebase?
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const glob = require('glob');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const autoprefixer = require('autoprefixer');
const statsSettings = {
all: false,
modules: true,
maxModules: 0,
errors: true,
warnings: false,
moduleTrace: true,
errorDetails: true,
timings: true,
performance: true,
builtAt: true,
};
const {
rootDir,
srcDir,
assetsDir,
stylesDir,
buildDir,
sitepackageDir,
publicPath,
} = require('./config');
const chunks = glob.sync(path.join(rootDir, srcDir, 'pages/**/index.js'))
.reduce((obj, file) => {
const name = path.basename(path.dirname(file));
return {
...obj,
[name]: file,
};
}, {});
module.exports = env => {
return {
mode: env.production ? 'production' : 'development',
context: path.join(rootDir, srcDir),
entry: chunks,
output: {
path: path.join(rootDir, buildDir),
filename: '[name].js',
publicPath: env.production ? publicPath : '',
},
devtool: env.production ? false : 'cheap-module-eval-source-map',
devServer: {
contentBase: path.join(rootDir, buildDir),
inline: true,
proxy: {
'/api/v0': 'http://localhost:4000',
},
},
watchOptions: {
ignored: env.watch ? 'node_modules' : '',
aggregateTimeout: 300,
},
stats: env.watch ? statsSettings : 'normal',
module: {
rules: [
{
test: /\.vue$/,
include: [
path.join(rootDir, srcDir),
require.resolve('bootstrap-vue'),
],
loader: 'vue-loader',
},
{
test: /\.js$/,
include: [
path.join(rootDir, srcDir),
require.resolve('bootstrap-vue'),
],
loader: 'babel-loader',
},
{
test: /\.(css|scss)$/,
use: [
env.production ? MiniCssExtractPlugin.loader : 'vue-style-loader',
'css-loader',
{
loader: 'postcss-loader',
options: {
plugins: [
autoprefixer({
browsers: ['>1%', 'last 2 versions', 'not ie < 11'],
}),
],
},
},
{
loader: 'sass-loader',
options: {
includePaths: [
path.join(rootDir, srcDir, stylesDir),
],
},
},
],
},
{
test: /\.(jpg|jpeg|png|gif|webp|svg|eot|otf|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$/,
loader: 'file-loader',
options: {
name: `${assetsDir}/_processed_/[name].[hash:4].[ext]`,
},
},
],
},
optimization: {
runtimeChunk: {
name: '_runtime',
},
splitChunks: {
cacheGroups: {
// we need to figure out if it's worth having a common chunk
// or if each entry chunk should be somewhat self-contained
common: {
chunks: 'initial',
name: '_common',
minChunks: 2,
minSize: 0,
},
vendor: {
test: /node_modules/,
chunks: 'initial',
name: '_vendor',
enforce: true,
},
},
},
},
resolve: {
extensions: ['.js', '.json', '.vue'],
alias: {
'#app': path.join(rootDir, srcDir),
// although we're using single file components that can be pre-compiled,
// we want to dynamically mounting them in the DOM html.
// this is way we need to alias 'vue' to use the runtime + compiler build here.
// see: https://vuejs.org/v2/guide/installation.html#Runtime-Compiler-vs-Runtime-only
vue$: 'vue/dist/vue.esm.js',
},
},
plugins: [
new webpack.DefinePlugin({
PAGES: JSON.stringify(Object.keys(chunks)),
}),
new VueLoaderPlugin(),
...plugHtmlTemplates(),
...plugExtractCss(env),
...plugCopyAssets(),
],
};
};
function plugHtmlTemplates () {
return glob.sync(path.join(rootDir, srcDir, 'pages/**/template.html'))
.map(template => {
const name = path.basename(path.dirname(template));
return {
template,
filename: `${name}.html`,
chunks: ['_runtime', '_vendor', '_styles', '_common', name],
};
})
.map(htmlConfig => new HtmlWebpackPlugin(htmlConfig));
}
function plugExtractCss (env) {
if (!env.production) return [];
return [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[name].css',
}),
];
}
function plugCopyAssets () {
const assetsSrcPath = path.join(rootDir, srcDir, assetsDir);
if (!fs.existsSync(assetsSrcPath)) return [];
return [
new CopyWebpackPlugin([
{ from: assetsSrcPath, to: path.join(rootDir, buildDir, path.basename(assetsDir)) },
// this is required for the icons to be selectable in the backend
{ from: path.join(assetsSrcPath, 'icons/'), to: path.join(rootDir, sitepackageDir, 'Resources/Public/Icons/') },
// this is required for avatars to be available; we must not check them in in fileadmin since they would
// prevent having the dir linked by Deployer during a deployment
{ from: path.join(rootDir, '../packages/users/Resources/Private/Images/Avatars/'), to: path.join(rootDir, buildDir, 'static/avatars/') },
]),
];
}
The question is whether you can improve the performance by using different plugins or summarizing steps...
I have a similar configuration. My configuration built ~33 seconds. I added a cache-loader package and decrease build time to ~17 seconds.
npm install --save-dev cache-loader
config:
rules: [
//rules here
{
test: /\.vue$/,
use: [
{
loader: 'cache-loader',
options: {}
},
{
loader: 'vue-loader',
options: vueLoaderConfig
}
],
},
{
test: /\.js$/,
use: [
{
loader: 'cache-loader',
options: {}
},
{
loader: 'babel-loader'
}
],
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
}
]
With this config I get an app.bundle.js, app.map, app.css. The problem is that app.map contains only the css related code. If I don't use ExtractTextPlugin then the sourcemap contains all the css and js related code but I have to keep css in a separate file. If I don't get map for css that's fine but for js it is a must have.
// webpack.common.config
var webpack = require('webpack');
var helpers = require('./helpers');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var webpackPostcssTools = require('webpack-postcss-tools');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var autoprefixer = require('autoprefixer');
var postcssImport = require('postcss-import');
var map = webpackPostcssTools.makeVarMap('src/css/index.css');
var ngAnnotatePlugin = require('ng-annotate-webpack-plugin');
const METADATA = {
baseUrl: '/'
};
module.exports = {
metadata: METADATA,
entry: {
'app': './src/js/app.js',
'vendor': './src/vendor.js'
},
resolve: {
extensions: ['', '.js'],
root: helpers.root('src'),
modulesDirectories: ['node_modules']
},
module: {
preLoaders: [
{ test: /\.js$/, loaders:['eslint', 'source-map-loader'], exclude: /node_modules/ }
],
loaders: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.json$/,
loader: 'json-loader'
},
{
test: /\.css$/,
loader: ExtractTextPlugin.extract('style-loader', 'css?sourceMap&importLoaders=1!postcss-loader?sourceMap')
},
{
test: /\.html$/,
loader: 'raw-loader',
exclude: [helpers.root('src/index.html')]
},
{
test: /\.woff(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "url-loader?limit=10000&minetype=application/font-woff"
}, {
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "file-loader"
}
]
},
plugins: [
new ngAnnotatePlugin({
add: true,
}),
new ExtractTextPlugin("[name].css", { allChunks: true }),
new webpack.optimize.OccurenceOrderPlugin(true),
new webpack.optimize.CommonsChunkPlugin({
name: helpers.reverse(['vendor', 'app']),
minChunks: Infinity
}),
new CopyWebpackPlugin([{
from: 'src/res',
to: 'res'
}, {
from: 'src/templates',
to: 'templates'
}
}
]),
new HtmlWebpackPlugin({
template: 'src/index.html',
chunksSortMode: 'none'
}),
],
postcss: function (webpack) {
return [
//webpackPostcssTools.prependTildesToImports,
postcssImport({ addDependencyTo: webpack }),
require('postcss-custom-properties')({
variables: map.vars
}),
require('postcss-custom-media')({
extensions: map.media
}),
require('postcss-calc'),
autoprefixer
];
},
node: {
global: 'window',
crypto: 'empty',
module: false,
clearImmediate: false,
setImmediate: false
},
};
// webpack.dev.config
var helpers = require('./helpers');
var webpackMerge = require('webpack-merge');
var commonConfig = require('./webpack.common.js');
var DefinePlugin = require('webpack/lib/DefinePlugin');
const ENV = process.env.ENV = process.env.NODE_ENV = 'development';
const METADATA = webpackMerge(commonConfig.metadata, {
host: 'localhost',
port: 8000,
ENV: ENV
});
module.exports = webpackMerge(commonConfig, {
debug: true,
metadata: METADATA,
devtool: 'source-map',
output: {
path: helpers.root('www'),
filename: '[name].bundle.js',
sourceMapFilename: '[name].map',
chunkFilename: '[id].chunk.js'
},
plugins: [
new DefinePlugin({
'ENV': JSON.stringify(METADATA.ENV)
}),
],
devServer: {
port: METADATA.port,
host: METADATA.host,
historyApiFallback: true,
watchOptions: {
aggregateTimeout: 300,
poll: 1000
}
},
eslint: {
configFile: './.eslintrc.js',
emitError: false,
emitWarning: false,
fix: true
},
node: {
global: 'window',
crypto: 'empty',
process: true,
module: false,
clearImmediate: false,
setImmediate: false
}
});
The issue seems to be that ExtractTextPlugin overwrites other sourcemaps, according to this discussion: https://github.com/webpack/extract-text-webpack-plugin/issues/119
You can fix this issue by ensuring that each output file that gets a sourcemap gets a different filename, like this:
sourceMapFilename: '[file].map'
I have the following problem when running the webpack dev server:
when I run npm start, it show the following:
➜ directory git:(staging) ✗ npm start
directory #1.0.0 start directory
BUILD_DEV=1 BUILD_STAGING=1 ./node_modules/webpack-dev-server/bin/webpack-dev-server.js
http://localhost:8080/
webpack result is served from /undefined/
content is served from
directory
404s will fallback to /index.html
Hash: 75773622412153d5f921
Version: webpack 1.12.11
Time: 43330ms
I guess the problem might because the following line:
webpack result is served from /undefined/
When I open the browser at http://localhost:8080/, it appear as follow:
Cannot GET /
and there is no thing in the console.
Do you have any ideas for this problem ?
UPDATE: WEBPACK CONFIG FILE
const webpack = require('webpack');
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const merge = require('webpack-merge');
const nodeModulesDir = path.resolve(__dirname, 'node_modules');
const deps = [
'moment/min/moment.min.js',
'underscore/underscore-min.js',
];
/* Include SASS path here if you want to this in your sass files:
* #import 'bourbon';
*/
const bourbon = require('node-bourbon').includePaths;
const TARGET = process.env.npm_lifecycle_event;
const ROOT_PATH = path.resolve(__dirname);
const SASS_DEPS = [bourbon].toString();
const BUILD_NUMBER = process.env.CI_BUILD_NUMBER;
const common = {
entry: path.resolve(ROOT_PATH, 'app/index.js'),
output: {
filename: BUILD_NUMBER + '-[hash].js',
path: path.resolve(ROOT_PATH, 'build'),
publicPath: `/${BUILD_NUMBER}/`,
},
module: {
loaders: [
{
test: /\.scss$/,
loaders: ['style', 'css', 'sass?includePaths[]=' + SASS_DEPS],
include: path.resolve(ROOT_PATH, 'app'),
},
{
test: /\.css$/,
loaders: [
'style',
'css?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
'sass?includePaths[]=' + SASS_DEPS,
'postcss'
],
include: path.resolve(ROOT_PATH),
exclude: /(pure\/grids|Grids).*\.css$/,
},
{
test: /(pure\/grids|Grids).*\.css$/,
loaders: [
'style',
'css',
'sass?includePaths[]=' + SASS_DEPS,
],
include: path.resolve(ROOT_PATH),
},
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'url-loader?limit=10000&minetype=application/font-woff',
},
{ test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: 'file-loader',
},
{
test: /\.json$/,
loader: 'json',
},
],
},
plugins: [
new HtmlWebpackPlugin({
title: 'My App',
template: path.resolve(ROOT_PATH, 'app/index.html'),
inject: 'body',
minify: {
removeComments: true,
collapseWhitespace: true,
},
}),
new webpack.DefinePlugin({
__DEV__: JSON.stringify(JSON.parse(process.env.BUILD_DEV || 'false')),
__STAGING__: JSON.stringify(JSON.parse(process.env.BUILD_STAGING || 'false')),
__API_HOST__: JSON.stringify(process.env.BUILD_STAGING ? 'my.api' : 'my.api'),
}),
],
resolve: {
alias: {
'styles': path.resolve(ROOT_PATH, 'app/styles'),
},
extensions: ['', '.js', '.jsx', '.json'],
},
postcss: function() {
return [
require('postcss-import'),
require('autoprefixer'),
require('postcss-cssnext'),
]
}
};
if (TARGET === 'start' || !TARGET) {
module.exports = merge(common, {
output: {
filename: '[hash].js',
path: path.resolve(ROOT_PATH, 'build'),
publicPath: '/',
},
devtool: 'eval-source-map',
module: {
loaders: [
{
test: /\.jsx?$/,
loaders: [
'react-hot',
'babel-loader'
],
include: path.resolve(ROOT_PATH, 'app'),
},
],
},
devServer: {
colors: true,
historyApiFallback: true,
hot: true,
inline: true,
progress: true,
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
],
});
} else if (TARGET === 'build' || TARGET === 'builds') {
const config = {
resolve: {
alias: {},
},
module: {
loaders: [
{
test: /\.jsx?$/,
loader: 'babel-loader',
include: path.resolve(ROOT_PATH, 'app'),
},
],
noParse: [],
},
plugins: [
new webpack.optimize.UglifyJsPlugin({
minimize: true,
compressor: {
screw_ie8: true,
warnings: false,
},
compress: {
warnings: false,
},
output: {
comments: false,
},
}),
new webpack.optimize.DedupePlugin(),
new webpack.DefinePlugin({
'process.env': { 'NODE_ENV': JSON.stringify(process.env.NODE_ENV) },
}),
],
};
deps.forEach((dep) => {
const depPath = path.resolve(nodeModulesDir, dep);
config.resolve.alias[dep.split(path.sep)[0]] = depPath;
config.module.noParse.push(depPath);
});
module.exports = merge(common, config);
}
Same problem occurred to me when i started using babel-loader > 6.
It was fixed by adding contentBase in webpack dev server configuration.
In my case it looked like this
new WebPackDevServer(webpack(config), {
publicPath: config.output.publicPath,
hot: true,
historyApiFallback: true,
contentBase: __dirname + '/public'
}).listen(3000, 'localhost')
I would be great to see your webpack config file to pin point the exact problem, but from the error message, there could be multiple problem
Make sure you are on the right port
Make sure your webpack config has
path and public path setup
Make sure you have contentBase setup as
well
Without seeing your webpack file and more concrete detail, it is quite hard to pinpoint the issue. But you can always go to https://webpack.github.io/docs/webpack-dev-server.html for information on how to set it up.