How to set host within vue.config.js from .env file - vue.js

I have following setup within my app:
.env
VUE_APP_API_BASE_URL=http://localhost:8000/v5/
VUE_APP_HTTPS=true
VUE_APP_HOST=local.ei.run
I'm setting the env variables within the vue.config.js and however I am trying to work out a way to call them within there as follows
// vue.config.js
var webpack = require('webpack')
module.exports = {
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
'process.env': {
'API_BASE_URL': JSON.stringify(process.env.VUE_APP_API_BASE_URL),
'HOST': JSON.stringify(process.env.VUE_APP_HOST)
}
})
]
},
// options...
devServer: {
open: process.platform === 'darwin',
host: process.env.HOST,
https: false,
disableHostCheck: true
}
}
So basically how can I set my host dynamically based off the env?

Related

Workbox Webpack Plugin and Webpack Dev Server issue

I'm starting to use webpack-workbox-plugin to inject service worker into application. My project is an ASP.NET Core web application that runs over IIS Express.
This is my development webpack config file:
const MODULE_BUILD_DIR = path.resolve(__dirname, './wwwroot/dist/assets/');
const workboxPlugin = require('workbox-webpack-plugin');
process.env.NODE_ENV = "development";
const config = {
mode: "development",
target: "web",
devtool: "cheap-module-source-map",
context: __dirname, // string (absolute path!)
entry: [
'#babel/polyfill',
'font-awesome/scss/font-awesome.scss',
'./wwwroot/js/main.js',
],
output: {
path: MODULE_BUILD_DIR,
filename: '[name].bundle.js',
chunkFilename: '[id].chunk.js',
},
// ...
plugins: [
// ...
new workboxPlugin.GenerateSW({
swDest: 'sw.js',
clientsClaim: true,
skipWaiting: true,
}),
],
devServer: {
contentBase: path.resolve(__dirname, './'),
historyApiFallback: false,
inline: true,
open: false,
port: 9099,
hot: true,
https: true,
},
// ...
}
And this is the function i call over my main.js:
export default function setServiceWorker() {
if ('serviceWorker' in navigator) {
window.addEventListener('load', () => {
navigator.serviceWorker.register('/sw.js').then((registration) => {
console.log('SW registered: ', registration);
}).catch((registrationError) => {
console.log('SW registration failed: ', registrationError);
});
});
}
}
But when i run application, client doesn't find sw.js file becuse it's allocated over webpack dev server path, so not in IIS Express app path.
DevTool messages:
A bad HTTP response code (500) was received when fetching the script.
---
SW registration failed: TypeError: Failed to register a ServiceWorker
for scope ('https://localhost:44357/') with script ('https://localhost:44357/sw.js'):
A bad HTTP response code (500) was received when fetching the script.
What could be a solution for it?
Thank you
Solved using clean-webpack-plugin and write-file-webpack-plugin:
plugins: [
new CleanWebpackPlugin(),
new WorkboxPlugin.GenerateSW({
swDest: 'sw.js',
clientsClaim: true,
skipWaiting: true,
}),
new WriteFilePlugin(),
],
but not sure it's the best way

Different variable value in Vue.js + Webpack in dev server vs build

I'm working on a Vue.js project which is running Webpack in local development & builds static files for deployment.
There is a variable apiDomain which needs to change from:
http://localhost.api/ - in local development
to
https://api.example.com/ - in the static build files
I've been trying to get my head around environmental variables but I'm not sure how they work in Webpack vs Vue.js.
What is the correct way to setup a Vue.js variable so it's different between local development & the static build files?
You can adapt this idea for your needs:
import axios from "axios";
const env = process.env.NODE_ENV || "development";
console.log(`we are on [${env}] environment`);
const addr = {
production: "https://rosetta-beer-store.io",
development: "http://127.0.0.1:3000",
};
const api = axios.create({
headers: {"x-api-key": "my-api-key", "x-secret-key": ""},
baseURL: addr[env],
});
export const beerservice = {
list: params => api.get("/beer/list", {params}),
find: id => api.get(`/beer/${id}`),
};
export const mediaservice = {
url: id => (id ? `${addr[env]}/media/${id}` : `${addr[env]}/icon.svg`),
};
By using the process.env.NODE_ENV (available on development and build time) you can not only to set the correct profile for the app services endpoints but also manage any tweak you need on your build scripts:
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const webpack = require("webpack");
module.exports = {
mode: process.env.NODE_ENV || "development",
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.html$/,
loader: "html-loader"
},
{
test: /\.(png|svg|jpg|gif|woff|woff2|eot|ttf|otf)$/,
use: ["file-loader"]
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"]
}
]
},
resolve: {
extensions: ["*", ".js", ".jsx"]
},
entry: "./src/main.jsx",
output: {
filename: "build.js",
path: path.resolve(__dirname, "dist")
},
devtool:
process.env.NODE_ENV == "development" ? "inline-source-map" : undefined,
devServer: {
contentBase: "./dist",
hot: true
},
plugins: [
new CleanWebpackPlugin(["dist"]),
new HtmlWebpackPlugin({
template: "./index.html"
}),
new webpack.HotModuleReplacementPlugin()
]
};
You can see more examples on this github project, but the general idea is to take advantage of node at the build time

How to output single build.js file for vue production build

I'm using vue-cli 2.9.6, and created a vue project using vue init webpack <project name>.
When I call vue run build, it is creating a number of different js files (and names change each time...):
vendor.20d54e752692d648b42a.js
vendor.20d54e752692d648b42a.js.map
app.ed70f310595763347909.js
app.ed70f310595763347909.js.map
manifest.2ae2e69a05c33dfc65f8.js
manifest.2ae2e69a05c33dfc65f8.js.map
And also css files like this:
app.a670fcd1e9a699133143a2b144475068.css
app.a670fcd1e9a699133143a2b144475068.css.map
I would like the output to simply be 2 files:
build.js { for all js }
styles.css { for all css }
How can I achieve this?
for preventing creation of vendor.js and manifest.js just remove following code from webpack.prod.conf.js
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks (module) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
minChunks: Infinity
}),
To prevent sourceMaps set in config/index.js the variable productionSourceMap from true to false
Changing name of app.js to build.js can be obtained modifying the entry and outputproperties in webpack.base.conf.js this way:
entry: {
build: './src/main.js'
},
output: {
path: config.build.assetsRoot,
filename: utils.assetsPath('js/[name].js'),
chunkFilename: utils.assetsPath('js/[id].[chunkhash].js')
},
Update name of the css output file updating options of ExtractTextPluginin webpack.prod.conf.js to filename: utils.assetsPath('css/styles.css'),
// vue.config.js
module.exports = {
chainWebpack: config => {
if(config.plugins.has('extract-css')) {
const extractCSSPlugin = config.plugin('extract-css')
extractCSSPlugin && extractCSSPlugin.tap(() => [{
filename: 'styles.css',
chunkFilename: 'styles.css'
}])
}
},
configureWebpack: {
output: {
filename: 'build.js',
chunkFilename: 'build.js'
}
}
}
or
module.exports = {
configureWebpack: {
optimization: {
splitChunks: false
}
},
filenameHashing: false
}

vue.js webpack problem: can't add plugin to vue.config.js with configureWebpack

vue.js webpack problem: I can't add a plugin to vue.config.js with configureWebpack
I created a vue.js project with vue cli 3. I am following the example in:
https://cli.vuejs.org/guide/webpack.html
My vue.config.js:
let webpack = require('webpack');
module.exports = {
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
__TEST_MESSAGE__: JSON.stringify('howdy there!')
})
]
},
};
The resolved webpack config looks like:
{
mode: 'production',
...
plugins: [
/* config.plugin('vue-loader') */
new VueLoaderPlugin(),
/* config.plugin('define') */
new DefinePlugin(
{
'process.env': {
VUE_APP_CLI_UI_URL: '""',
NODE_ENV: '"production"',
BASE_URL: '"/"'
}
}
),
/* config.plugin('case-sensitive-paths') */
new CaseSensitivePathsPlugin(),
...
/////////////////////////////////////////////////////
// Inserted note for SO: This is messed up! Should
// be:
// new DefinePlugin({ __TEST_MESSAGE__: '"howdy there!"' })
/////////////////////////////////////////////////////
{
definitions: {
__TEST_MESSAGE__: '"howdy there!"'
}
}
],
...
}
configureWebPack is supposed to merge my plugins with the vue defined plugins. Why is it stripping the DefinePlugin class out and just including the argument to the constructor in the plugins array?
Because Vue already includes the DefinePlugin, you need to modify it using Webpack's chain API instead of attempting to add a new one.
module.exports = {
chainWebpack: config => {
config.plugin('define').tap(args => {
args[0].__TEST_MESSAGE__ = JSON.stringify('howdy there!')
return args
})
}
}
This results in the following config (just an example)...
new DefinePlugin(
{
'process.env': {
NODE_ENV: '"development"',
BASE_URL: '"/"'
},
__TEST_MESSAGE__: '"howdy there!"'
}
),
See https://cli.vuejs.org/guide/webpack.html#modifying-options-of-a-plugin

Correctly configure webpack-dev-middleware with vuejs project

I'm new to webpack so it's probably a stupid mistake on my part.
This is my project setup (root, atleast the relevant part):
+-- public
| |
| +-- index.html
|
+-- src
| |
| +-- App.vue
| +-- main.js
| +-- assets
|
+-- package.json
|
+-- webpack.config.js
Now I would like to use the webpack-dev(and hot)-middleware to serve my index.html and create a bundle in memory from my src folder. Now I can get the middleware set up (via the npm page) and I see the bundle gets created (through logging in console) but two things are not clear to me:
How to serve index.html
How to use the bundle thats created in memory?
Can somebody please explain how that middleware works exactly? This is my webpack config file (which is needed to plug into the middleware, it's just a copy of the webpack config file that gets created through the vue-cli):
var path = require('path')
var webpack = require('webpack')
module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
// vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true
},
devtool: '#eval-source-map'
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
I know this is probably not the correct configuration, can someone maybe point out some things?
Thanks in advance for your help!
Edit (this setup works):
My server.js now:
var express = require('express');
var logger = require('morgan');
var bodyParser = require('body-parser');
var exphbs = require('express-handlebars');
var helmet = require('helmet');
var redis = require('redis');
var redisAdapter = require('socket.io-redis');
var app = express();
var server = require('http').Server(app);
var io = require('socket.io')(server);
// use the redis adapter to create sticky sessions, this is needed because of the different clusters
io.adapter(redisAdapter( require('./app/lib/config').credentials.redis.url ));
//setup security ===============================================================
require('./app/lib/security-setup')(app, helmet);
// configuration ===============================================================
app.use(logger('dev')); // log every request to the console
// set up our express application ==============================================
// Make the body object available on the request
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
//set handlebars as default templating engine
app.engine('handlebars', exphbs());
app.set('view engine', 'handlebars');
// serve the static content ====================================================
if (app.settings.env === 'development') {
var webpackConfig = require('./webpack.config.js')
var compiler = require('webpack')(webpackConfig)
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
})
var hotMiddleware = require('webpack-hot-middleware')(compiler)
app.use(devMiddleware)
app.use(hotMiddleware)
} else {
app.use(express.static(__dirname + '/public'));
}
// set up global variables =====================================================
app.use(function(req, res, next) {
//set the io object on the response, so we can access it in our routes
res.io = io;
next();
});
// routes ======================================================================
require('./app/routes.js')(app); // load our routes and pass in our app
// export so bin/www can launch ================================================
module.exports = {app: app, server: server};
my ./bin/www:
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../server').app;
var cluster = require('cluster');
var debug = require('debug')('temp:server');
var http = require('http');
var numCPUs = process.env.WORKERS || require('os').cpus().length;
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
if (cluster.isMaster) {
// Fork workers.
for (var i = 0; i < numCPUs; i++) {
cluster.fork();
}
// If a worker dies, log it to the console and start another worker.
cluster.on('exit', function(worker, code, signal) {
console.log('Worker ' + worker.process.pid + ' died.');
cluster.fork();
});
// Log when a worker starts listening
cluster.on('listening', function(worker, address) {
console.log('Worker started with PID ' + worker.process.pid + '.');
});
} else {
/**
* Create HTTP server.
*/
var server = require('../server').server;
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
}
// The rest of the bin/www file.....
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string' ? 'Pipe ' + port : 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string' ? 'pipe ' + addr : 'port ' + addr.port;
debug('Listening on ' + bind);
}
My working webpack.config.js:
var path = require('path')
var webpack = require('webpack')
var HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
entry: [
'webpack/hot/dev-server',
'webpack-hot-middleware/client',
'./src/main.js'
],
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
// vue-loader options go here
}
},
{
test: /\.less$/,
loader: "style!css!less"
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.common.js'
}
},
devServer: {
historyApiFallback: true,
noInfo: true
},
devtool: '#eval-source-map',
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, 'public/index.html'),
inject: true
}),
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
}
if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
How to serve index.html
To serve the index.html file you need to have a dev server running. It sounds like you are successfully doing this based on your logging of the creation of your bundle in memory. However I can't see a file for it in your set up? I've assumed another file below called: dev-server.js and it would be your entry point to serving your app, i.e. npm run dev:
package.json
"scripts": {
"dev": "node dev-server.js",
...
In webpack this dev server is generally going to be express and it's the config that you pass to your express server that will serve your index.html. As you are wanting hot-reloading you will pass express your webpack config through your middleware layers.
For hot reloading you'll need two main middlewares:
webpack-dev-middleware
webpack-hot-middleware
Then you will need to pass your config to webpack and pass your webpack compiler to the middleware, i.e.
dev-server.js
var app = require('express')()
var webpackConfig = require('./webpack.config.js')
var compiler = require('webpack')(webpackConfig)
var devMiddleware = require('webpack-dev-middleware')(compiler, {
publicPath: webpackConfig.output.publicPath,
})
var hotMiddleware = require('webpack-hot-middleware')(compiler)
app.use(devMiddleware)
app.use(hotMiddleware)
Now the key file becomes your webpack config, referenced above as: ./webpack.config.js
This leads to your next question: How to use the bundle thats created in memory?
The file you posted above looks to be about right and the key parts in regards to using the bundle are held within the output, you have:
webpack.config.js
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
You are creating the bundle at dist/build.js relative to the current working directory. This is essentially where you need to point any references to that file within your index.html, i.e. <script src="/dist/build.js"></script>
How you do this can be manual however we'd often add a further webpack plugin to automatically build this script tag within your output html (again in this case in memory):
webpack.config.js
plugins: [
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, 'public/index.html'),
inject: true
}),
...
The HtmlWebpackPlugin is now essentially how you reference what the output file is called: filename and crucially where it is stored: template so if you wanted to move your index.html file this is where you tell webpack where to find it. The HtmlWebpackPlugin will now place the output 'index.html' at the publicPath referenced earlier, so to get to this file you would call /dist/index.html.
Finally you'll need some further plugins for hot reloading so your entire webpack plugins array will look like:
webpack.config.js
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin(),
// https://github.com/ampedandwired/html-webpack-plugin
new HtmlWebpackPlugin({
filename: 'index.html',
template: 'bar/index.html',
inject: true
})
]
Now we return to the dev-server.js file - or whatever yours is called that you are configuring express within - and fire up the configured express server:
dev-server.js
module.exports = app.listen(8080, function (err) {
if (err) {
console.log(err)
return
}
})
so with the above config you'd open the following uri: localhost:8080/dist/index.html