webpack DefinePlugin use external config.js - reactjs

I am new in webpack
I have this code in webpack.config.js
var path = require('path');
var webpack = require('webpack');
var pkg = require('./package.json');
var myconfig = require('./webpack.myconfig.js');
// bundle dependencies in separate vendor bundle
var dependencies = Object.keys(pkg.dependencies).filter(function (el) {
//exclude font packages from vendor bundle & css-toggle-switch
if (el.indexOf('font') !== -1 || el.indexOf('css-toggle-switch') !== -1) {
return false;
}
else return true;
});
module.exports = {
entry: {
libs: dependencies,
main: './src/index'
},
output: {
path: path.join(__dirname, myconfig.buildPath),
publicPath: myconfig.uiURL,
filename: 'dist/js/[name].js',
chunkFilename: '[id].[name].js'
},
plugins: [
new webpack.DefinePlugin({
DEBUG_MODE: JSON.stringify(false),
TIMEOUT: JSON.stringify(30000),
API_URL: JSON.stringify(myconfig.apiUrl),
"process.env": {
NODE_ENV: JSON.stringify("production")
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'libs',
filename: 'dist/js/libs.js',
minChunks: Infinity
})
],
};
and this is myconfig.js
myconfig = {
uiURL: 'http://example.com/',
apiUrl: 'http://api.example.com/api/'
};
module.exports = myconfig;
and if I run this syntax
webpack -p --config webpack.config.js --progress --colors
I will get the result like
/dist/js/libs.js
/dist/js/main.js
but I want the result not like this, I want the result to be:
/dist/js/myconfig.js
/dist/js/libs.js
/dist/js/main.js
What really I want is,
I want in main.js file, it will use myconfig.apiUrl as depedencies,
so when I deployed to production or qserver, I just change myconfig.js.
Thank you

webpack.myconfig.js is used in webpack config file so you have to rebuild every time when webpack.myconfig.js is changed.
You could use myconfig.json and send http request to get it dynamically.

If you just want to get myconfig.js in /dist/js/, you can use CopyWebpackPlugin. It can copy static files from one path to another.
Add a new new line plugins section like :
plugins: [
new CopyWebpackPlugin([{ from: APP_DIR + '\\images', to: APP_DIR + '\\build\\images' }]),
new webpack.DefinePlugin({
DEBUG_MODE: JSON.stringify(false),
TIMEOUT: JSON.stringify(30000),
API_URL: JSON.stringify(myconfig.apiUrl),
"process.env": {
NODE_ENV: JSON.stringify("production")
}
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'libs',
filename: 'dist/js/libs.js',
minChunks: Infinity
})
],
Here CopyWebpackPlugin copies file from one path to another.
Make sure you var CopyWebpackPlugin = require('copy-webpack-plugin');at top of webpack.config.js & added same in package.json & installed via npm.

Related

remove absulte path from webpack output

Well, I build my app using webpack in production mode, I have the output files containing absolute paths like :
E:/xxxx/xxxx/src/app/core/components/lib/RadioButtonGroupEntry.js
This is my webpack configuration:
resolve: {
//When require, do not have to add these extensions to file's name
extensions: ["", ".js", ".jsx"],
},
//Render source-map file for final build
//output config
output: {
path: buildPath, //Path of output file
filename: '[name]-[chunkhash].js', //Name of output file
publicPath: '/'
},
node: {
fs: 'empty'
},
plugins: [
//Minify the bundle
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'production')
}),
new webpack.optimize.UglifyJsPlugin({
compress: {
//supresses warnings, usually from module minification
warnings: false
}
}),
//Allows error warnings but does not stop compiling. Will remove when eslint is added
new webpack.NoErrorsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: Infinity,
}),
// new InlineManifestWebpackPlugin({
// name: 'webpackManifest'
// }),
new WebpackMd5Hash(),
// new ManifestPlugin(),
// new ChunkManifestPlugin({
// filename: "chunk-manifest.json",
// manifestVariable: "webpackManifest"
// }),
new HtmlWebpackPlugin({template: 'src/www/index.ejs'}),
//Transfer Files
new TransferWebpackPlugin([{from: 'www'}], path.resolve(__dirname,'src'))]
I think my webpack.config is messed up and I would like some help to figure out what is wrong with it so that the absolute path will be removed.
Thanks.
Maybe you could try to configure the output path property of your webpack configuration object with path and the node __dirname global object, as this:
output: {
path: path.resolve(__dirname, 'yourBuildFolder')
}
I had a similar issue (I use multiple entries) and solved it with path.relative():
{
entry: {
'head': [
`./${path.relative(__dirname, 'my/source/path.js')}`,
...
]
},
...
}

I can't find the vender.js when I use webpack

I am using webpack and having a problem.I want to product a html in the public but I can't succeed.
when I use npm run dev ,I encounter a problem
this is my github
https://github.com/wohuifude123/webpack20180315
supplement
I have read you answer many times, and then I modidy webpack.dll.js
output: {
path: __dirname + 'public/dist',
filename: '[name].[chunkhash:8].js',
library: '[name]_[chunkhash:8]'
},
and then I modify the webpack.dev.js
const path = require('path');
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
// 引入dev-server配置文件
let BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// a third party
const manifest = require('./vender-manifest.json');
const _venderName = manifest.name.split('_');
const venderName = _venderName[0] + '.' + _venderName[1];
module.exports = merge(common, {
output: { //打包路径
//filename: '[name].bundle.js', //出口文件名
// filename: '[name].[chunkhash].js',
// 可以使用__dirname变量获取当前模块文件所在目录的完整绝对路径
path: __dirname + 'dist', //打包路径
publicPath:'dist/', // 指定publicPath
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
library: '[venderName].js'
},
devtool: 'source-map',
devServer: {
contentBase: [path.join(__dirname, "./public")], // 本地服务器 加载页面 所在的目录
host: '127.0.0.1',
compress: true,
port: 6600,
open: false // 将自动打开浏览器
},
plugins:[
new BundleAnalyzerPlugin({
analyzerMode: 'server', // static/disabled
analyzerHost: '127.0.0.1',
analyzerPort: 9900,
openAnalyzer: false
})
]
});
finally I modify the webpack.common.js
plugins: [
new CleanWebpackPlugin(['dist'], { // 清除 dist 文件中的内容
exclude: [venderName + '.js'] // 排除 提取出的 第三方的 js
}),
new webpack.DllReferencePlugin({
context: __dirname,
manifest: require('./vender-manifest.json') // 加载 manifest.json
}),
new HtmlWebpackPlugin({
filename: './index.html',
template: './src/index.html',
//favicon: './src/favicon.ico',
alwaysWriteToDisk: true // 是否开启 new HtmlWebpackHarddiskPlugin()
}),
new HtmlWebpackIncludeAssetsPlugin({
assets: [venderName + '.js'],
append: false // 不会被 webpack 自动打包
}),
// new HtmlWebpackIncludeAssetsPlugin({
// assets: ['config/env-config.js'],
// append: false, // 不会被 webpack 自动打包
// hash: true
// }),
new HtmlWebpackHarddiskPlugin(), // 将[venderName + '.js']和['env-config.js']放进 index.html 中
new webpack.DefinePlugin({ // 创建一个编译时可以配置的全局常量
PRODUCTION: JSON.stringify(true),
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
})
]
Although I have read your answer carefully, I can't understand details.
I try to modify many places ,but the product can't work .
There are 2 problems in your code:
You are not matching the dll library to your app's output library:
Your webpack.dll.js:
output: {
// some properties
library: '[name]_[chunkhash:8]'
}
//...
new webpack.DllPlugin({
name: '[name]_[chunkhash:8]'
})
Your webpack.dev.js:
const manifest = require('./vender-manifest.json');
//...
module.exports = merge(common, {
output: {
// some properties
library: manifest.name // this was missing
}
}
What I see you were doing was matching the DllPlugin name to the dll output file library, which is not the case.
The webpack dll plugin docs inform to Keep the name consistent with output.library, but applying to where you are using the dll (while using DllReferencePlugin), not where you are creating them (DllPlugin).
You are not creating the dll in the dist folder:
Your webpack dll config looks like:
output: {
path: __dirname + '/dist'
}
which writes your dll file into rootDir/dist and not rootDir/public/dist as you rather wanted.
So the fix for this one would be to just change it to path: __dirname + 'public/dist'.
After those fixes your code started to work for me. If you have any more questions feel free to ask ;)

React production shows blank page

i have a problem with a webpack build, the command i run is
cross-env NODE_ENV=production webpack --config webpack.prod.js
and the file webpack prod is:
var webpack = require('webpack');
var webpackMerge = require('webpack-merge');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var commonConfig = require('./webpack.common.js');
var path = require('path');
const ENV = process.env.NODE_ENV = process.env.ENV = 'production';
module.exports = webpackMerge(commonConfig, {
devtool: 'source-map',
output: {
path: path.join(process.cwd(), '/public'),
publicPath: '/',
filename: '[name].[hash].js'
},
plugins: [
//new webpack.NoErrorsPlugin(),
new webpack.optimize.DedupePlugin(),
new webpack.optimize.UglifyJsPlugin({
mangle: {
keep_fnames: true,
except: ['$super']
}
}),
new ExtractTextPlugin('[name].[hash].css'),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production')
}
})
]
});
webpack.common.js is
var webpack = require('webpack');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var path = require('path');
var pkgBower = require('./package.json');
module.exports = {
entry: {
'app': './main.js'
},
resolve: {
root: path.join(__dirname, ''),
modulesDirectories: ['node_modules', 'bower_components'],
extensions: ['', '.js', '.jsx']
},
module: {
loaders: [...]
},
devServer: {
outputPath: path.join(__dirname, 'public')
},
plugins: [
new HtmlWebpackPlugin({
template: process.env.NODE_ENV == 'development' ? 'index.html' : 'index.prod.html',
baseUrl: process.env.NODE_ENV == 'development' ? '/' : '/'
})
]
};
i can run the build but unfortunatelly when i open index.html it shows a blank page to me, i want to include this SPA in a spring boot project but I do not know how ;)
Thanks!
Solved! was a problem of "browserHistory"
If you use the "browserHistory" as history manager your webpack needs a node.js server to run, using a "hashHistory" you can use it as a normal web page!
See
Why is React Webpack production build showing Blank page?
First things first, which version of webpack are you using Lorenzo? Probably due to syntax, it's 1.X.
First, check in your package.json file which version is. Then, if it's really 1.x you can build in debug mode.
export default {
entry: [
'./src/Client.js'
],
debug: true
}
Inside your webpack.common.js
Check the error, paste here.
I hope it helps, welcome to StackOverflow, here are a few notes that can improve our community =)
Try to put "main":"index.js" in package.json file
That solved my problem.
"main": "index.js",
"scripts": {
...
},
Happy to help.

How to watch certain node_modules changes with webpack-dev-server

I'm currently experimenting with a monorepo architecture.
What I would like to do is in my web package where I run webpack dev server I'd like it to watch certain node_modules (symlinked local packages) for changes and trigger a "rebuild".
This way I'd be able to build dependencies separately and my browser would react to those changes.
My webpack config is the following:
var loaders = require('./../../../build/loaders-default');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: ['./src/index.ts'],
output: {
filename: 'build.js',
path: path.join(__dirname, 'dist')
},
resolve: {
extensions: ['.ts', '.js', '.json']
},
resolveLoader: {
modules: ['node_modules']
},
devtool: 'inline-source-map',
devServer: {
proxy: [
{
context: ['/api-v1/**', '/api-v2/**'],
target: 'https://other-server.example.com',
secure: false
}
]
},
plugins: [
new HtmlWebpackPlugin({
template: './src/index.html',
inject: 'body',
hash: true
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.jQuery': 'jquery',
'window.jquery': 'jquery'
})
],
module:{
loaders: loaders
}
};
Loaders are just the usual stuff included.
You can config in in webpack.config file or in WebpackDevServer option, to watch for changes also in node_modules (i think that by default webpack watching for changes in all files)
https://webpack.js.org/configuration/watch/#watchoptions-ignored
in the following example webpack ignored all changes in node_modules folder except specific module.
watchOptions: {
ignored: [
/node_modules([\\]+|\/)+(?!some_npm_module_name)/,
/\some_npm_module_name([\\]+|\/)node_modules/
]
}
ignored[0] = Regex to ignore all node_modules that not started with some_npm_module_name
ignored[1] = Regex to ignore all node_modules inside some_npm_module_name
You may also used this link npm linked modules don’t find their dependencies
UPDATE: I'm currently using Next.js 11, and it seems this is no longer necessary.
Granted this question is not regarding Next.js or any specific framework, I'd like to post an answer related to Next.js here since I arrived here from Google as others might also.
Here is what worked for me in my next.config.js:
module.exports = {
// ...
webpackDevMiddleware: config => {
// Don't ignore all node modules.
config.watchOptions.ignored = config.watchOptions.ignored.filter(
ignore => !ignore.toString().includes('node_modules')
);
// Ignore all node modules except those here.
config.watchOptions.ignored = [
...config.watchOptions.ignored,
/node_modules\/(?!#orgname\/.+)/,
/\#orgname\/.+\/node_modules/
];
return config;
},
// ...
}
This targets a specific organization of packages. If you need to just target a specific package:
module.exports = {
// ...
webpackDevMiddleware: config => {
// Don't ignore all node modules.
config.watchOptions.ignored = config.watchOptions.ignored.filter(
ignore => !ignore.toString().includes('node_modules')
);
// Ignore all node modules except those here.
config.watchOptions.ignored = [
...config.watchOptions.ignored,
/node_modules([\\]+|\/)+(?!my-node-module)/,
/\my-node-module([\\]+|\/)node_modules/
];
return config;
},
// ...
}
This builds on Elhay's answer.
snapshot.managedPaths
A common use case for managedPaths would be to exclude some folders from node_modules, e.g. you want webpack to know that files in the node_modules/#azure/msal-browser folder are expected to change, which can be done with a regular expression like the one below:
module.exports = {
snapshot: {
managedPaths: [
/^(.+?[\\/]node_modules[\\/](?!(#azure[\\/]msal-browser))(#.+?[\\/])?.+?)[\\/]/,
],
},
};

variable config file based on environment - reactjs, webpack

I need bunch of global variables in my reactjs components(example: hostnames, token, api urls, etc) based on the environment. but I don't want to add it to the js individually. I would like to create project.config file to set up prod:{hostname:example.com, api-url:prod, etc} and dev:{hostname:localhost.com, api-url:dev, etc}, I installed loose-envify, but I have to specify for each var.
var path = require('path');
var webpack = require('webpack');
var ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://example.com:3000',
'webpack/hot/only-dev-server',
'./src/index'
],
output: {
path: path.join(__dirname, 'dist'),
filename: 'bundle.js',
publicPath: '/static/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.DefinePlugin({'process.env.NODE_ENV': JSON.stringify('production')}),
new ExtractTextPlugin("static/super.css", {
allChunks: true
})
],
module: {
loaders: [{
test: /\.js$/,
loaders: ['react-hot', 'babel'],
include: path.join(__dirname, 'src')
},
{ test: /\.scss$/,
loaders: ["style", "css", "sass"],
include: path.join(__dirname, 'src')
}
]
}
};
Did you try to stringify a config json that can have some common and overridden properties for dev or prod?
Which will be given to the new webpack.DefinePlugin({...})?
I was trying to try something similar and tried following which seems to work fine.
In your webpack config add a DefinePlugin. Following is my webconfig:-
plugins: [
new BundleTracker({filename: './webpack-stats.json'}),
new webpack.DefinePlugin({
'process.env': {
'NODE_ENV': JSON.stringify(process.env.environment),
}
})
],
Now while compiling use the following commands:-
environment=local webpack (for local)
environment=development webpack(for dev)
environment=production webpack(for prod)
Now if you see I have set 'NODE_ENV' with the cli input so when 'NODE_ENV' is production as value, the webpack automatically minifies your output bundle.
Now say you have API url declared in a file(I had Constants.jsx), so I added following to constants.jsx. So basically you can read the NODE_ENV set in webpack config in this Constants.jsx and import them in your components from where APIS are called by exporting it from here.
const api_url=function(){
let api_url='';
if(process.env.NODE_ENV == 'local'){
api_url= 'http://localhost:8002/api/v0';
}
else if(process.env.NODE_ENV == 'development'){
api_url = 'https://development/api/v0';
}
else if(process.env.NODE_ENV == 'production'){
api_url = 'https://production/api/v0';
}
return api_url;
}
export const url= api_url();
Hope it helped!

Resources