I'm attempting to use webpack v3 to test long term caching. When I build twice by webpack(just make a change to index.jsx file), and the hash value changed to vendor file.
webpack.config.js
Reference:Caching
const webpack = require('webpack')
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const ChunkManifestPlugin = require('chunk-manifest-webpack-plugin')
const InlineManifestWebpackPlugin = require('inline-manifest-webpack-plugin')
const InlineChunkManifestHtmlWebpackPlugin = require('inline-chunk-manifest-html-webpack-plugin')
// const CompressionPlugin = require('compression-webpack-plugin')
/**
* global variable of config
*/
// replace localhost with 0.0.0.0 if you want to access
// your app from wifi or a virtual machine
const host = process.env.HOST || '0.0.0.0'
const port = process.env.PORT || 8080
const allowedHosts = ['192.168.19.61']
const sourcePath = path.join(__dirname, './site')
const distPath = path.join(__dirname, './dist')
const htmlTemplate = './index.template.ejs'
const stats = {
assets: true,
children: false,
chunks: false,
hash: false,
modules: false,
publicPath: false,
timings: true,
version: false,
warnings: true,
colors: {
green: '\u001b[32m'
}
}
/**
* webpack config
*/
module.exports = function (env) {
const nodeEnv = env && env.production ? 'production' : 'development'
const isProd = nodeEnv === 'production'
/**
* Mete Design Webpack V3.1 Buiding Informations
*/
console.log('--------------Mete Design Webpack V3.1--------------')
console.log('enviroment:' + nodeEnv)
console.log('host:' + host)
console.log('port:' + port)
console.log('dist path:' + distPath)
console.log('platform:' + env.platform)
console.log('-----------------Mete Design Group------------------')
/**
* common plugin
*/
const plugins = [
new webpack.optimize.CommonsChunkPlugin({
// vendor chunk
names: ['manifest', 'vendor'] // the name of bundle
}), // new webpack.optimize.CommonsChunkPlugin({ // name: 'manifest', // minChunks: Infinity // }), // setting production environment will strip out // some of the development code from the app // and libraries
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify(nodeEnv)
}
}), // create css bundle // allChunks set true is for code splitting
new ExtractTextPlugin({
filename: 'css/[name]-[contenthash].css',
allChunks: true
}), // create index.html
new HtmlWebpackPlugin({
template: htmlTemplate,
inject: true,
production: isProd,
minify: isProd && {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true
}
}),
new InlineManifestWebpackPlugin({
name: 'webpackManifest'
}),
new InlineChunkManifestHtmlWebpackPlugin({
manifestPlugins: [
new ChunkManifestPlugin({
filename: 'manifest.json',
manifestVariable: 'webpackManifest',
inlineManifest: false
})
]
})
]
if (isProd) {
/**
* production envrioment plugin
*/
plugins.push(
// minify remove some of the dead code
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false,
screw_ie8: true,
conditionals: true,
unused: true,
comparisons: true,
sequences: true,
dead_code: true,
evaluate: true,
if_return: true,
join_vars: true
},
mangle: false
}),
new webpack.optimize.ModuleConcatenationPlugin())
} else {
/**
* development enviroment plugin
*/
plugins.push(
// make hot reloading work
new webpack.HotModuleReplacementPlugin(),
// show module names instead of numbers in webpack stats
new webpack.NamedModulesPlugin(),
// don't spit out any errors in compiled assets
new webpack.NoEmitOnErrorsPlugin()
// load DLL files
// new webpack.DllReferencePlugin({context: __dirname, manifest: require('./dll/react_manifest.json')}),
// new webpack.DllReferencePlugin({context: __dirname, manifest: require('./dll/react_dom_manifest.json')}),
// // make DLL assets available for the app to download
// new AddAssetHtmlPlugin([
// { filepath: require.resolve('./dll/react.dll.js') },
// { filepath: require.resolve('./dll/react_dom.dll.js') }
// ])
)
}
return {
devtool: isProd ? 'source-map' : 'cheap-module-source-map',
entry: {
main: ['babel-polyfill', path.join(sourcePath, 'index.js')],
// static lib
vendor: ['react', 'react-dom', 'react-router-dom']
},
output: {
filename: isProd ? 'js/[name]-[hash].bundle.js' : 'js/[name].bundle.js',
chunkFilename: isProd ? 'js/[id]-[chunkhash].bundle.js' : 'js/[id].bundle.js',
path: distPath,
publicPath: './'
},
// loader
module: {
rules: [
// js or jsx loader
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: [['es2015', {
'modules': false
}], 'react', 'stage-0'],
cacheDirectory: true // Since babel-plugin-transform-runtime includes a polyfill that includes a custom regenerator runtime and core.js, the following usual shimming method using webpack.ProvidePlugin will not work:
}
}
}, // css loader
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [{
loader: 'css-loader',
options: {
minimize: isProd
}
}],
publicPath: '/'
})
}, // scss loader
/* {
test: /\.scss$/,
exclude: /node_modules/,
use: ExtractTextPlugin.extract({
publicPath: '/',
fallback: 'style-loader',
use: [
// {loader: 'autoprefixer-loader'},
{
loader: 'css-loader',
options: {
minimize: isProd
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true,
includePaths: [sourcePath, path.join(__dirname, './src')]
}
}
]
})
}, */
// images loader
{
test: /\.(png|svg|jpg|gif)$/,
loader: 'url-loader?limit=8024&name=assets/images/[name]-[hash].[ext]'
},
{
test: /\.(woff2?|otf|eot|ttf)$/i,
loader: 'url-loader?limit=8024&name=assets/fonts/[name].[ext]',
options: {
publicPath: distPath
}
},
{
test: /\.md$/,
loader: 'raw-loader'
}
]
},
resolve: {
extensions: ['.js', '.jsx'],
modules: [path.resolve(__dirname, 'node_modules'), sourcePath],
alias: {
md_components: path.resolve(__dirname, 'src/components'),
md_midware: path.resolve(__dirname, 'src/md-midware')
}
},
plugins,
stats,
// webpack dev server
devServer: {
// 文件路劲,一般静态文件需要
contentBase: '/',
// 是否启用gzip压缩
compress: true,
// 是否启用热替换
hot: true,
port,
// 开启任意ip访问
host,
// 允许列表中host访问
allowedHosts,
// 取消host列表安全检查,开发环境启用,默认关闭,开启则allowedHosts无效
// disableHostCheck: true,
// 关闭webpack重启打包信息,错误和警告仍然会显示
noInfo: true,
// 浏览器全屏显示编译器错误信息
overlay: true,
// 公共文件,浏览器可直接访问,HMR必须
publicPath: '/'
}
}
}
fisrt build
js/vendor-a674cd02275fdf4760bd.bundle.js 343 kB 1 [emitted] [big] vendor
second build(just update index.jsx)
js/vendor-f8d5fc2097878041c158.bundle.js 343 kB 1 [emitted] [big] vendor
Both hashes change even though I only updated the index file.
Help
Anyone can help me to check this problem? Thanks.
Github Repo:webpack_long_term_cache_test
filename in output use chunkhash, and reset the CommonsChunkPlugin name: ['vendor', 'manifest']
Related
I'm creating a PWA react application in which I configure the manifest.json file and serviceWroker.js file.
In the development mode, it works fine but when I create production build using webpack, manifest.json file does not load in the Build folder.
Does anyone know what's the issue?
Here is my webpack.config.js file
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const WebpackRTLPlugin = require('webpack-rtl-plugin');
const WebpackMessages = require('webpack-messages');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const del = require('del');
const webpack = require('webpack');
// theme name
const themeName = 'metronic';
// global variables
const rootPath = path.resolve(__dirname);
const distPath = rootPath + '/src';
const mainConfig = function() {
const isEnvDevelopment = false;
const isEnvProduction = true;
return {
mode: 'production',
stats: 'errors-only',
performance: {
hints: false
},
externals: [ 'jspdf', 'jspdf-autotable' ],
entry: './src/index.js',
output: {
// main output path in assets folder
path: path.resolve(__dirname, 'dist'),
// output path based on the entries' filename
// filename: '[name].js',
filename: isEnvProduction
? 'static/js/[name].[contenthash:8].js'
: isEnvDevelopment && 'static/js/bundle.js',
// TODO: remove this when upgrading to webpack 5
futureEmitAssets: true,
// There are also additional JS chunk files if you use code splitting.
chunkFilename: isEnvProduction
? 'static/js/[name].[contenthash:8].chunk.js'
: isEnvDevelopment && 'static/js/[name].chunk.js',
// We inferred the "public path" (such as / or /my-project) from homepage.
// We use "/" in development.
publicPath: '/artbot/app/'
},
resolve: { extensions: [ '.scss', '.css','.mjs','.jsx', '.js', '.json' ] },
optimization: {
minimize: true,
namedChunks: true,
nodeEnv: 'production',
removeAvailableModules: true,
removeEmptyChunks: true,
mergeDuplicateChunks: true,
minimizer: [ new OptimizeCssAssetsPlugin(), new TerserPlugin({ cache: true }) ],
splitChunks: {
chunks: "all"
}
},
plugins: [
// webpack log message
new WebpackMessages({
name: themeName,
logger: (str) => console.log(`>> ${str}`)
}),
new BundleAnalyzerPlugin(),
new webpack.optimize.AggressiveMergingPlugin(),
new HtmlWebpackPlugin({
title: 'Custom Template',
template: 'public/index.html',
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true
}
}),
// create css file
new MiniCssExtractPlugin({
filename: 'static/css/[name].css'
}),
new WebpackRTLPlugin({
filename: 'static/css/[name].rtl.css',
minify: true
}),
{
apply: (compiler) => {
// hook name
compiler.hooks.afterEmit.tap('AfterEmitPlugin', (compilation) => {
(async () => {
await del.sync(distPath + '/sass/*.js', { force: true });
})();
});
}
}
],
module: {
rules: [
{
test: /\.(js|mjs|jsx|ts|tsx)$/,
// exclude: /#babel(?:\/|\\{1,2})runtime/,
exclude: /node_modules/,
loader: require.resolve('babel-loader'),
options: {
babelrc: true,
plugins: [
[
require.resolve('babel-plugin-named-asset-import'),
{
loaderMap: {
svg: {
ReactComponent: '#svgr/webpack?-svgo,+titleProp,+ref![path]'
}
}
}
]
]
}
},
{
test: /\.css$/,
loader: 'css-loader'
},
{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
{
loader: 'resolve-url-loader',
options: {
removeCR: true
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
},
{
test: /\.(png|jpg|svg)$/,
loader: 'file-loader',
options: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]',
esModule: false
}
//loader: 'url-loader?limit=8192'
},
{
test: /\.(woff2|eot|ttf|woff)$/,
loader: 'url-loader'
},
{
test: /\.json$/,
loader: 'file-loader',
type: 'javascript/auto',
exclude: /node_modules/,
options: {
name: 'static/json/[name].[hash:8].[ext]'
}
},
{
test: /\.html$/i,
loader: 'html-loader'
}
]
}
};
};
module.exports = function() {
return [ mainConfig() ];
};
I am trying to integrate Creative Tim's Material Kit Pro React frontend with the generator for the backend provided here
I generated a material ui react app using the back end yo generator. I then installed the additional dependencies specified in the Creative Tim file. At that point, I get an error. SCSS files that previously loaded in the original app now throw an error that says:
Uncaught Error: Cannot find module "./LoadingSpinner.scss"
at webpackMissingModule (LoadingSpinner.js:4)
I have copied both webpack.config.js files but they are so different, I can't get a grip on where to start integrating them.
Has anyone tried to use both packages?
Material Kit Pro React webpack.config.js has:
const path = require('path');
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
process.env.NODE_ENV = process.env.NODE_ENV || 'development';
if (process.env.NODE_ENV === 'test') {
require('dotenv').config({ path: '.env.test'});
} else if (process.env.NODE_ENV === 'development') {
require('dotenv').config({ path: '.env.development'});
}
module.exports = (env) => {
const isProduction = env ==='production';
const CSSExtract = new ExtractTextPlugin('styles.css');
return {
entry: './src/index.js',
output: {
path: path.join(__dirname, 'public', 'dist'),
filename: 'bundle.js'
},
// resolve: { alias: { Assets: path.resolve(__dirname, 'src/assets') } },
module: {
rules: [{
loader: 'babel-loader',
test: /\.js$/,
exclude: /node_modules/
}, {
test: /\.s?css$/,
use: CSSExtract.extract({
use: [
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
})
}]
},
plugins: [
CSSExtract,
new webpack.DefinePlugin({
'process.env.REACT_APP_FIREBASE_API_KEY': JSON.stringify(process.env.REACT_APP_FIREBASE_API_KEY),
'process.env.REACT_APP_FIREBASE_AUTH_DOMAIN': JSON.stringify(process.env.REACT_APP_FIREBASE_AUTH_DOMAIN),
'process.env.REACT_APP_FIREBASE_DATABASE_URL': JSON.stringify(process.env.REACT_APP_FIREBASE_DATABASE_URL),
'process.env.REACT_APP_FIREBASE_PROJECT_ID': JSON.stringify(process.env.REACT_APP_FIREBASE_PROJECT_ID),
'process.env.REACT_APP_FIREBASE_STORAGE_BUCKET': JSON.stringify(process.env.REACT_APP_FIREBASE_STORAGE_BUCKET),
'process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID': JSON.stringify(process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID)
})
],
devtool: isProduction ? 'source-map' : 'inline-source-map',
devServer: {
contentBase: path.join(__dirname, 'public'),
historyApiFallback: true,
publicPath: '/dist/'
}
};
};
Backend generator has:
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const project = require('../project.config')
const inProject = path.resolve.bind(path, project.basePath)
const inProjectSrc = file => inProject(project.srcDir, file)
const __DEV__ = project.env === 'development'
const __TEST__ = project.env === 'test'
const __PROD__ = project.env === 'production'
const config = {
entry: {
normalize: [inProjectSrc('normalize')],
main: [inProjectSrc(project.main)]
},
devtool: project.sourcemaps ? 'source-map' : false,
output: {
path: inProject(project.outDir),
filename: __DEV__ ? '[name].js' : '[name].[chunkhash].js',
publicPath: project.publicPath
},
resolve: {
modules: [inProject(project.srcDir), 'node_modules'],
extensions: ['*', '.js', '.jsx', '.json']
},
externals: project.externals,
module: {
rules: []
},
plugins: [
new webpack.DefinePlugin(
Object.assign(
{
'process.env': { NODE_ENV: JSON.stringify(project.env) },
__DEV__,
__TEST__,
__PROD__
},
project.globals
)
)
],
node: {
// disable node constants so constants.js file is used instead (see https://webpack.js.org/configuration/node/)
constants: false
}
}
// JavaScript
// ------------------------------------
config.module.rules.push({
test: /\.(js|jsx)$/,
exclude: [
/node_modules/,
/redux-firestore\/es/,
/react-redux-firebase\/es/
// Add other packages that you are npm linking here
],
use: [
{
loader: 'babel-loader',
query: {
cacheDirectory: true,
// ignore root .babelrc (Check issue #59 for more details)
babelrc: false,
plugins: [
'lodash',
'transform-decorators-legacy',
'babel-plugin-transform-class-properties',
'babel-plugin-syntax-dynamic-import',
'babel-plugin-transform-export-extensions',
[
'babel-plugin-transform-runtime',
{
helpers: true,
polyfill: false, // we polyfill needed features in src/normalize.js
regenerator: true
}
],
[
'babel-plugin-transform-object-rest-spread',
{
useBuiltIns: true // we polyfill Object.assign in src/normalize.js
}
]
],
presets: [
'babel-preset-react',
[
'babel-preset-env',
{
targets: {
ie9: true,
uglify: true,
modules: false
}
}
]
]
}
}
]
})
// Styles
// ------------------------------------
const extractStyles = new ExtractTextPlugin({
filename: 'styles/[name].[contenthash].css',
allChunks: true,
disable: __DEV__
})
config.module.rules.push({
test: /\.(sass|scss)$/,
loader: extractStyles.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
sourceMap: project.sourcemaps,
modules: true,
importLoaders: 2,
localIdentName: '[name]__[local]___[hash:base64:5]',
minimize: {
autoprefixer: {
add: true,
remove: true,
browsers: ['last 2 versions']
},
discardComments: {
removeAll: true
},
discardUnused: false,
mergeIdents: false,
reduceIdents: false,
safe: true,
sourcemap: project.sourcemaps
}
}
},
{
loader: 'sass-loader',
options: {
sourceMap: project.sourcemaps,
includePaths: [inProjectSrc('styles')]
}
}
]
})
})
config.plugins.push(extractStyles)
// Images
// ------------------------------------
config.module.rules.push({
test: /\.(png|jpg|gif)$/,
loader: 'url-loader',
options: {
limit: 8192
}
})
// Fonts
// ------------------------------------
;[
['woff', 'application/font-woff'],
['woff2', 'application/font-woff2'],
['otf', 'font/opentype'],
['ttf', 'application/octet-stream'],
['eot', 'application/vnd.ms-fontobject'],
['svg', 'image/svg+xml']
].forEach(font => {
const extension = font[0]
const mimetype = font[1]
config.module.rules.push({
test: new RegExp(`\\.${extension}$`),
loader: 'url-loader',
options: {
name: 'fonts/[name].[ext]',
limit: 10000,
mimetype
}
})
})
// HTML Template
// ------------------------------------
config.plugins.push(
new HtmlWebpackPlugin({
template: inProjectSrc('index.html'),
inject: true,
minify: {
collapseWhitespace: true
}
})
)
// Development Tools
// ------------------------------------
if (__DEV__) {
config.entry.main.push(
`webpack-hot-middleware/client.js?path=${
config.output.publicPath
}__webpack_hmr`
)
config.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin()
)
}
// Bundle Splitting
// ------------------------------------
if (!__TEST__) {
const bundles = ['normalize', 'manifest']
if (project.vendors && project.vendors.length) {
bundles.unshift('vendor')
config.entry.vendor = project.vendors
}
config.plugins.push(
new webpack.optimize.CommonsChunkPlugin({ names: bundles })
)
}
// Production Optimizations
// ------------------------------------
if (__PROD__) {
config.plugins.push(
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: !!config.devtool,
comments: false,
compress: {
warnings: false,
screw_ie8: true,
conditionals: true,
unused: true,
comparisons: true,
sequences: true,
dead_code: true,
evaluate: true,
if_return: true,
join_vars: true
}
})
)
}
module.exports = config
I can see the css loaders are different, but I can't see what to do to make the Creative Tim files work with this backend. Has anyone figured this out?
I have tried adding tests to the module exports statement in the generator so that it reads as follows:
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "sass-loader",
// options: {
// includePaths: ["absolute/path/a", "absolute/path/b"]
// }
}],
}],
},
That attempt produces a new error that reads:
web.dom.iterable.js:19 Uncaught Error: Module build failed:
#import 'base';
^
Invalid CSS after "": expected 1 selector or at-rule, was "var content = requi"
I also tried adding style-loader as an additional loader to the webpack.config file (alongside css-loader and sass-loader), but that produces the following error:
Invalid CSS after "": expected 1 selector or at-rule, was "var content = requi"
(line 1, column 1)
at Object../node_modules/css-loader/index.js!./node_modules/sass-loader/lib/loader.js!./node_modules/extract-text-webpack-plugin/dist/loader.js??ref--2-0!./node_modules/style-loader/index.js!./node_modules/css-loader/index.js??ref--2-2!./node_modules/sass-loader/lib/loader.js??ref--2-
Others who have had problems getting the css configured suggest that there may be config defined elsewhere. I don't seem to have that. I am about halfway through deleting all the references to css in the backend generated file. That was working (up to newProjectTile) but now that still generates failure to build css error.
Driving me crazy that config is so complicated across these tools. If anyone has added a custom theme to the backend generator (regardless of whether it's the Creative Tim theme or otherwise), have you found a way to compile CSS? Any tips would be very much appreciated.
Currently, my webpack.config file is as follows - errors galore in the console and still no closer to an idea for how to resolve them.
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const project = require('../project.config')
const inProject = path.resolve.bind(path, project.basePath)
const inProjectSrc = file => inProject(project.srcDir, file)
const __DEV__ = project.env === 'development'
const __TEST__ = project.env === 'test'
const __PROD__ = project.env === 'production'
const CSSExtract = new ExtractTextPlugin('styles.css');
const config = {
entry: {
normalize: [inProjectSrc('normalize')],
main: [inProjectSrc(project.main)]
},
devtool: project.sourcemaps ? 'source-map' : false,
output: {
path: inProject(project.outDir),
filename: __DEV__ ? '[name].js' : '[name].[chunkhash].js',
publicPath: project.publicPath
},
resolve: {
modules: [inProject(project.srcDir), 'node_modules'],
extensions: ['*', '.js', '.jsx', '.json']
},
externals: project.externals,
module: {
rules: [{
loader: 'babel-loader',
test: /\.js$/,
exclude: /node_modules/
}, {
test: /\.s?css$/,
use: CSSExtract.extract({
use: [
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'style-loader',
options: {
sourceMap: true
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
})
}]
},
plugins: [
CSSExtract,
new webpack.DefinePlugin(
Object.assign(
{
'process.env': { NODE_ENV: JSON.stringify(project.env) },
__DEV__,
__TEST__,
__PROD__
},
project.globals
)
)
],
node: {
// disable node constants so constants.js file is used instead (see https://webpack.js.org/configuration/node/)
constants: false
}
}
// JavaScript
// ------------------------------------
config.module.rules.push({
test: /\.(js|jsx)$/,
exclude: [
/node_modules/,
/redux-firestore\/es/,
/react-redux-firebase\/es/
// Add other packages that you are npm linking here
],
use: [
{
loader: 'babel-loader',
query: {
cacheDirectory: true,
// ignore root .babelrc (Check issue #59 for more details)
babelrc: false,
plugins: [
'lodash',
'transform-decorators-legacy',
'babel-plugin-transform-class-properties',
'babel-plugin-syntax-dynamic-import',
'babel-plugin-transform-export-extensions',
[
'babel-plugin-transform-runtime',
{
helpers: true,
polyfill: false, // we polyfill needed features in src/normalize.js
regenerator: true
}
],
[
'babel-plugin-transform-object-rest-spread',
{
useBuiltIns: true // we polyfill Object.assign in src/normalize.js
}
]
],
presets: [
'babel-preset-react',
[
'babel-preset-env',
{
targets: {
ie9: true,
uglify: true,
modules: false
}
}
]
]
}
}
]
})
// Styles
// ------------------------------------
const extractStyles = new ExtractTextPlugin({
filename: 'styles/[name].[contenthash].css',
allChunks: true,
disable: __DEV__
})
config.module.rules.push({
test: /\.(sass|scss)$/,
loader: extractStyles.extract({
fallback: 'style-loader',
use: [
{
loader: 'css-loader',
options: {
sourceMap: project.sourcemaps,
modules: true,
importLoaders: 2,
localIdentName: '[name]__[local]___[hash:base64:5]',
minimize: {
autoprefixer: {
add: true,
remove: true,
browsers: ['last 2 versions']
},
discardComments: {
removeAll: true
},
discardUnused: false,
mergeIdents: false,
reduceIdents: false,
safe: true,
sourcemap: project.sourcemaps
}
}
},
{
loader: 'style-loader'
},
{
loader: 'sass-loader',
options: {
sourceMap: project.sourcemaps,
includePaths: [inProjectSrc('styles')]
}
}
]
})
})
config.plugins.push(extractStyles)
// Images
// ------------------------------------
config.module.rules.push({
test: /\.(png|jpg|gif)$/,
loader: 'url-loader',
options: {
limit: 8192
}
})
// Fonts
// ------------------------------------
;[
['woff', 'application/font-woff'],
['woff2', 'application/font-woff2'],
['otf', 'font/opentype'],
['ttf', 'application/octet-stream'],
['eot', 'application/vnd.ms-fontobject'],
['svg', 'image/svg+xml']
].forEach(font => {
const extension = font[0]
const mimetype = font[1]
config.module.rules.push({
test: new RegExp(`\\.${extension}$`),
loader: 'url-loader',
options: {
name: 'fonts/[name].[ext]',
limit: 10000,
mimetype
}
})
})
// HTML Template
// ------------------------------------
config.plugins.push(
new HtmlWebpackPlugin({
template: inProjectSrc('index.html'),
inject: true,
minify: {
collapseWhitespace: true
}
})
)
// Development Tools
// ------------------------------------
if (__DEV__) {
config.entry.main.push(
`webpack-hot-middleware/client.js?path=${
config.output.publicPath
}__webpack_hmr`
)
config.plugins.push(
new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin()
)
}
// Bundle Splitting
// ------------------------------------
if (!__TEST__) {
const bundles = ['normalize', 'manifest']
if (project.vendors && project.vendors.length) {
bundles.unshift('vendor')
config.entry.vendor = project.vendors
}
config.plugins.push(
new webpack.optimize.CommonsChunkPlugin({ names: bundles })
)
}
// Production Optimizations
// ------------------------------------
if (__PROD__) {
config.plugins.push(
new webpack.LoaderOptionsPlugin({
minimize: true,
debug: false
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: !!config.devtool,
comments: false,
compress: {
warnings: false,
screw_ie8: true,
conditionals: true,
unused: true,
comparisons: true,
sequences: true,
dead_code: true,
evaluate: true,
if_return: true,
join_vars: true
}
})
)
}
module.exports = config
I can't build a project with webpack because I'm getting a syntax error all the time.
Moreover when my friend runs the same code on Linux (I work on Windows 10) he doesn't get any errors and everything works fine.
Here is my webpack config
const path = require('path');
const autoprefixer = require('autoprefixer');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const WebpackMd5Hash = require('webpack-md5-hash');
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');
const DefinePlugin = require('webpack/lib/DefinePlugin');
const HMRPlugin = require('webpack/lib/HotModuleReplacementPlugin');
const LoaderOptionsPlugin = require('webpack/lib/LoaderOptionsPlugin');
const NamedModulesPlugin = require('webpack/lib/NamedModulesPlugin');
const OccurrenceOrderPlugin = require('webpack/lib/optimize/OccurrenceOrderPlugin');
const ProgressPlugin = require('webpack/lib/ProgressPlugin');
const UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
//=========================================================
// VARS
//---------------------------------------------------------
const NODE_ENV = process.env.NODE_ENV;
const DEVELOPMENT = NODE_ENV === 'development';
const PRODUCTION = NODE_ENV === 'production';
const HOST = process.env.HOST || '127.0.0.1';
const PORT = process.env.PORT || '3000';
//=========================================================
// LOADERS
//---------------------------------------------------------
const rules = {
js: {
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader',
},
json: {
test: /\.json$/,
loader: 'json-loader',
},
css: {
test: /\.css$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'resolve-url-loader', 'postcss-loader'],
}),
},
scss: {
test: /\.scss$/,
loader: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'resolve-url-loader', 'postcss-loader', 'sass-loader'],
}),
},
fonts: {
test: /\.(eot|svg|ttf|woff|woff2)$/,
loader: 'file-loader',
query: {
name: `[name].[ext]`,
publicPath: '/assets/fonts/',
}
},
images: {
test: /\.(svg|png|jpg|jpeg|gif)$/,
loader: 'file-loader',
query: {
limit: 10000,
name: `[name].[ext]`,
publicPath: '/assets/images/',
}
}
};
//=========================================================
// CONFIG
//---------------------------------------------------------
const config = {};
config.entry = {
polyfills: './src/application/polyfills.js',
main: ['./src/application/index.js'],
};
config.output = {
filename: 'assets/js/[name].js',
path: path.resolve('./dist'),
// publicPath: '/',
};
config.resolve = {
extensions: ['.js', '.json'],
modules: [
path.resolve('./src'),
'node_modules',
]
};
config.module = {
rules: [
rules.js,
rules.css,
rules.json,
rules.scss,
rules.fonts,
rules.images,
]
};
config.plugins = [
new LoaderOptionsPlugin({
debug: !PRODUCTION,
cache: !PRODUCTION,
minimize: PRODUCTION,
options: {
postcss: [
autoprefixer({
browsers: ['last 3 versions'],
})
],
sassLoader: {
outputStyle: PRODUCTION ? 'compressed' : 'expanded',
precision: 10,
sourceComments: false,
sourceMap: PRODUCTION,
}
}
}),
new DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(NODE_ENV),
}),
new OccurrenceOrderPlugin(true),
new NamedModulesPlugin(),
new CommonsChunkPlugin({
name: 'polyfills',
chunks: ['polyfills'],
}),
// This enables tree shaking of the vendors modules
new CommonsChunkPlugin({
name: 'vendor',
chunks: ['main'],
minChunks: module => /node_modules/.test(module.resource),
}),
new CommonsChunkPlugin({
name: ['polyfills', 'vendor'].reverse(),
}),
new CopyWebpackPlugin([
{
from: './src/assets',
to: 'assets',
ignore: ['**/*.scss'],
}
]),
new ExtractTextPlugin({
filename: 'assets/css/[name].css',
disable: !PRODUCTION,
allChunks: true,
}),
new HtmlWebpackPlugin({
filename: 'index.html',
hash: false,
inject: 'body',
chunksSortMode: 'dependency',
template: './src/index.html',
})
];
//=====================================
// DEVELOPMENT
//-------------------------------------
if (DEVELOPMENT) {
config.devtool = 'cheap-module-source-map';
config.entry.main.unshift(
'react-hot-loader/patch',
`webpack-dev-server/client?http://${HOST}:${PORT}`,
'webpack/hot/only-dev-server',
);
config.plugins.push(
new HMRPlugin(),
new ProgressPlugin(),
);
config.devServer = {
contentBase: path.resolve(__dirname, 'dist'),
historyApiFallback: true,
host: HOST,
hot: true,
port: PORT,
stats: {
cached: true,
cachedAssets: true,
children: false,
chunks: false,
chunkModules: false,
colors: true,
modules: false,
hash: false,
reasons: true,
timings: true,
version: false,
}
};
}
//=====================================
// PRODUCTION
//-------------------------------------
if (PRODUCTION) {
config.devtool = 'hidden-source-map';
config.plugins.push(
new WebpackMd5Hash(),
new UglifyJsPlugin({
comments: false,
compress: {
unused: true,
dead_code: true,
screw_ie8: true,
warnings: false,
},
mangle: {
screw_ie8: true,
}
})
);
}
module.exports = config;
And this is my package.json scripts
"scripts": {
"test": "jest",
"server:dev": "set NODE_ENV='development' && webpack-dev-server --color",
"start": "npm run server:dev",
"build": "set NODE_ENV='production' && webpack --color"
},
When I try to run "npm start", I have this error
C:\Users\vellgreen\Desktop\my_webpack_react\webpack.config.js:184
);
^
SyntaxError: Unexpected token )
when I put this into comment everything is working normal.
config.entry.main.unshift(
'react-hot-loader/patch',
`webpack-dev-server/client?http://${HOST}:${PORT}`,
'webpack/hot/only-dev-server',
);
config.plugins.push(
new HMRPlugin(),
new ProgressPlugin(),
);
When I run code for production everything is also fine.
My OS is Windows 10, webpack v3.1.0, npm v5.3.0, node v6.10.3.
Does anyone know what may cause such an error?
Trailing commas in functions are a relatively recent feature and Node started supporting it in version 8. Your friend is simply using a version that supports it (it's unrelated to the OS).
config.entry.main.unshift(
'react-hot-loader/patch',
`webpack-dev-server/client?http://${HOST}:${PORT}`,
'webpack/hot/only-dev-server',
// ^ --- remove this comma
);
config.plugins.push(
new HMRPlugin(),
new ProgressPlugin(),
// ^ --- and this comma
);
I was just following this guide
I have this code:
import React, { PropTypes, Component } from 'react';
import('contact-page').then(() => {});
I get this output:
This is my webpack file:
var webpack = require('webpack');
var packages = require('./package.json');
var path = require('path');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
var HtmlWebpackPlugin = require('html-webpack-plugin');
var filterDependencies = ['normalize.css', 'font-awesome'];
var dependencies = Object.keys(packages.dependencies).filter(f => !filterDependencies.some(fd => fd === f));
module.exports = {
entry: {
main: './src/index.js',
vendor: dependencies
},
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: Infinity,
}),
new ExtractTextPlugin("styles.css"),
new HtmlWebpackPlugin({
template: 'index.html'
})
],
module: {
rules: [
{
test: /\.js?$/,
use: [ 'babel-loader', ],
exclude: /node_modules/
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
}),
exclude: /node_modules/
},
{
test: /(\.png|\.jpg|\.otf)$/,
use: ['file-loader?name=[name].[ext]&publicPath=assets/&outputPath=assets/']
}
]
},
performance: {
hints: "warning", // enum
maxAssetSize: 200000, // int (in bytes),
maxEntrypointSize: 400000, // int (in bytes)
assetFilter: function (assetFilename) {
// Function predicate that provides asset filenames
return assetFilename.endsWith('.css') || assetFilename.endsWith('.js');
}
},
devtool: "source-map", // enum
target: "web", // enum
stats: "errors-only",
devServer: {
proxy: { // proxy URLs to backend development server
'/api': 'http://localhost:3000'
},
contentBase: path.join(__dirname, 'public'), // boolean | string | array, static file location
compress: true, // enable gzip compression
historyApiFallback: true, // true for index.html upon 404, object for multiple paths
hot: true, // hot module replacement. Depends on HotModuleReplacementPlugin
https: false, // true for self-signed, object for cert authority
noInfo: true, // only errors & warns on hot reload
// ...
}
};
For dynamin import I'm using babel-plugin-syntax-dynamic-import library - https://www.npmjs.com/package/babel-plugin-syntax-dynamic-import
After installation you have to extend module.rules sets to something like (as long as you want to mix es2015 and react):
module: {
rules: [
{
test: /\.js?$/,
use: {
loader: 'babel-loader',
options: {
presets: [['es2015', "react"]],
plugins: ['syntax-dynamic-import']
},
},
exclude: /node_modules/
},
},
It is described in tutorial https://webpack.js.org/guides/code-splitting-async/#usage-with-babel more detailed.
I need to output the js, images, fonts, css to different directories. Webpack is configured accordingly and placing the files in the correct directories in the distribution directory:
/dist
/dist/images
/dist/css
/dist/js
/dist/fonts
I also had to extract the css file and for that reason, I notice that the file-loader option that is used to place the fonts and images into the right directory does not generated the correct url, so then the files fail to load in the web browser.
http://foobar.com/assets/css/main.css
http://foobar.com/assets/css/assets/images/foobar.png
When expected,
http://foobar.com/assets/images/foobar.png
The webpack config file follows:
var path = require("path");
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var config = require('./config');
var CompressionPlugin = require("compression-webpack-plugin");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: [
'./src/js/index.js'
],
output: {
path: __dirname + '/dist',
filename: 'assets/js/bundle-[hash].js'
},
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loaders: ['babel-loader'] },
{ test: /\.scss$/, loader: ExtractTextPlugin.extract('style','css!sass') },
{ test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/, loader: 'file-loader?name=[name].[ext]&publicPath=assets&outputPath=fonts' },
{ test: /\.(jpg|png|gif|svg)$/i, loader: 'file-loader?name=[name].[ext]&publicPath=assets&outputPath=images/'}
]
},
plugins: [
new ExtractTextPlugin("assets/css/[name].css"),
new HtmlWebpackPlugin({
inject: true,
template: __dirname + '/src/' + 'index.html',
filename: 'index.html'
}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production'),
'PORT_NODE_SERVER': config.port.node_server_prod_port
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: true
}
}),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
mangle: true,
compress: {
warnings: false, // Suppress uglification warnings
pure_getters: true,
unsafe: true,
unsafe_comps: true,
screw_ie8: true
},
output: {
comments: false,
},
exclude: [/\.min\.js$/gi] // skip pre-minified libs
}),
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8
})
]
};
I found a solution. It seems that webpack v1 needs a hint about the base path to be able to solve this, for that reason the full base path is required, has follow:
var path = require("path");
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var config = require('./config');
var CompressionPlugin = require("compression-webpack-plugin");
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: [
'./src/js/index.js'
],
output: {
path: __dirname + '/dist',
filename: 'js/bundle-[hash].js',
publicPath: '/myapp/assets'
},
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loaders: ['babel-loader'] },
{ test: /\.scss$/, loader: ExtractTextPlugin.extract('style','css!sass') },
{ test: /\.(ttf|eot|svg|woff(2)?)(\?[a-z0-9=&.]+)?$/, loader: 'file-loader?name=/fonts/[name].[ext]' },
{ test: /\.(jpg|png|gif|svg)$/i, loader: 'file-loader?name=/images/[name].[ext]'}
]
},
plugins: [
new ExtractTextPlugin("css/[name]-[hash].min.css"),
new HtmlWebpackPlugin({
inject: true,
template: __dirname + '/src/' + 'index.html',
filename: 'index.html'
}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify('production'),
'PORT_NODE_SERVER': config.port.node_server_prod_port
}
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: true
}
}),
new webpack.optimize.AggressiveMergingPlugin(),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
mangle: true,
compress: {
warnings: false, // Suppress uglification warnings
pure_getters: true,
unsafe: true,
unsafe_comps: true,
screw_ie8: true
},
output: {
comments: false,
},
exclude: [/\.min\.js$/gi] // skip pre-minified libs
}),
new CompressionPlugin({
asset: "[path].gz[query]",
algorithm: "gzip",
test: /\.js$|\.css$|\.html$/,
threshold: 10240,
minRatio: 0.8
})
]
};
About the /myapp has in http://foobar.com/myapp and then http://foobar.com/myapp/assets/js/bundle-438348934.js and so http://foobar.com/myapp/assets/fonts/myfont.woff
Hope this helps!