Workbox Webpack Plugin and Webpack Dev Server issue - asp.net-core

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

Related

Production config Webpack build for a Rust, WebAssembly app to apache2 server

I have a Rust, Web assembly wasm app I need to deploy to an apache server. When upload the build, it doesn't run the software, it just shows a list of the files.
The build files look like this:
build
-0.bootstrap.js
-bootstap.js
-gfdgjkljlkjjiojohio.module.wasm
my webpack config looks like
const path = require('path');
module.exports = {
entry: "./bootstrap.js",
output: {
path: path.resolve(__dirname, "dist"),
filename: "bootstrap.js",
},
mode: "development",
devServer: {
//host: "0.0.0.0",
port: 8080,
}
};
Where boostrap.js imports the main index.js file
// A dependency graph that contains any wasm must all be imported
// asynchronously. This `bootstrap.js` file does the single async import, so
// that no one else needs to worry about it again.
import("./index.js")
.catch(e => console.error("Error importing `index.js`:", e));
But when I deploy to my apache server, to my domain, I don't get the software running.
Why isn't it running?
I had to use HtmlWebpackPlugin and change my webpack config to this
module.exports = {
entry: './bootstrap.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
filename: 'index.html',
inject: true,
template: path.resolve(__dirname, 'index.html'),
}),
]
}

How to enable dotenv variables for a file inside the /public folder in a Vue project?

I have very little experience with configuring Webpack, and I'am a bit overwhelmed by this issue.
I've been working on a Vue2 project built on top of this boilerplate. The project has a folder called public which contains the entry point file index.html. Inside that index.html file I can normally access .env environment variables (e.g. process.env.VUE_APP_PAGE_TITLE).
I've included an HTML fragment inside the public folder, navbar.html, because I want it to be available for other applications via https://example.com/public/navbar.html. However, I cannot seem to get my environment variables working inside ./public/navbar.html even though they work just fine in ./public/index.html. I assume this is a problem with my webpack config.
I know I can edit my Webpack config by editing a file in my project root called vue.config.js. This file contains a configureWebpack object, but I have no idea how to make it enable environment variables inside ./public/navbar.html. Any help would be appreciated.
EDIT:
Here's my vue.config.js:
const HtmlWebpackPlugin = require('html-webpack-plugin');
function resolveClientEnv() {
const env = {};
Object.keys(process.env).forEach((key) => {
env[key] = process.env[key];
});
env.BASE_URL = '/';
return env;
}
module.exports = {
configureWebpack: {
plugins: [
new HtmlWebpackPlugin({
// This is the generated file from the build, which ends up in public/navbar.html
filename: 'navbar.html',
// This is the source file you edit.
template: 'public/navbar.html',
templateParameters: (compilation, assets, pluginOptions) => {
let stats;
return Object.assign({
// make stats lazy as it is expensive
get webpack() {
return stats || (stats = compilation.getStats().toJson());
},
compilation,
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: pluginOptions,
},
}, resolveClientEnv());
},
}),
],
},
};
This is what my custom HTMLWebpackPlugin adds to the configuration according to vue inspect:
{
options: {
template: 'public/navbar.html',
templateContent: false,
templateParameters: function () { /* omitted long function */ },
filename: 'navbar.html',
hash: false,
inject: true,
compile: true,
favicon: false,
minify: 'auto',
cache: true,
showErrors: true,
chunks: 'all',
excludeChunks: [],
chunksSortMode: 'auto',
meta: {},
base: false,
title: 'Webpack App',
xhtml: false
},
childCompilerHash: undefined,
childCompilationOutputName: undefined,
assetJson: undefined,
hash: undefined,
version: 4
}
Use this standard plugin to generate navbar.html. https://github.com/jantimon/html-webpack-plugin.
If you read the docs, the templateParameters option is what you pass env variables to. Those variables will be available in navbar.html.
This is the same plugin that vue-cli uses for index.html. If you run the vue inspect command, you can see what options they provide to the plugin. You'll need to read the source code for resolveClientEnv() to see how it works.
Example:
/* config.plugin('html-portal') */
new HtmlWebpackPlugin(
{
templateParameters: (compilation, assets, pluginOptions) => {
// enhance html-webpack-plugin's built in template params
let stats
return Object.assign({
// make stats lazy as it is expensive
get webpack () {
return stats || (stats = compilation.getStats().toJson())
},
compilation: compilation,
webpackConfig: compilation.options,
htmlWebpackPlugin: {
files: assets,
options: pluginOptions
}
}, resolveClientEnv(options, true /* raw */))
},
minify: {
removeComments: true,
collapseWhitespace: true,
removeAttributeQuotes: true,
collapseBooleanAttributes: true,
removeScriptTypeAttributes: true
},
chunks: [
'chunk-vendors',
'chunk-common',
'portal'
],
template: 'C:\\Users\\Eric\\workspace\\arc-core\\portal\\client\\templates\\portal.html',
filename: 'portal.html',
title: 'Arc Portal'
}
),
That's a bit much, a minimal example would be:
new HtmlWebpackPlugin({
// This is the generated file from the build, which ends up in public/navbar.html
filename: 'navbar.html',
// This is the source file you edit.
template: 'templates/navbar.html',
templateParameters: {
MY_VAR: 'myVar'
}
}),

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

Require and import finds module, but proxyquireify does not?

As the question states, the requiring/importing of the module works fine in these cases:
const Session = require('../session.js').default;
or
import Session from '../session.js');
But I want to replace a module that is required inside session.js, so I tried to do that in a test with Proxyquireify:
const proxyquire = require('proxyquireify')(require);
const someStub = () => { return {}; };
someStub['#noCallThru'] = true;
const Session = proxyquire('../session.js', {
'some': someStub
}).default;
Then I get an error stating that the module '../session.js' cannot be found.
PhantomJS 1.9.8 (Linux 0.0.0) ERROR
Error: Cannot find module '../session.js'
My karma config is this:
module.exports = function(config) {
config.set({
basePath: '',
frameworks: ['browserify', 'jasmine'],
files: [
'spec/**/*Spec.js'
],
exclude: [
'spec/**/PlayerSpec.js'
],
preprocessors: {
'spec/**/*Spec.js': ['browserify']
},
browserify: {
debug: true,
transform: ['babelify']
},
reporters: ['progress', 'dots'],
port: 9876,
colors: true,
logLevel: config.LOG_INFO,
autoWatch: true,
browsers: ['PhantomJS'],
singleRun: false,
concurrency: Infinity
})
};
What could be wrong? Do you need any more information?
Just stumbled onto the same issue.
Noticed that proxyquireify did not inject require calls next to proxyquire ones for some reason, so I just ended up simply doing it myself, at least for now.
Try using something like this:
require('../session.js');
const Session = proxyquire('../session.js', ...);

Grunt express livereload and proxy does not work?

I want to launch a web server from grunt with livereload and that proxies Rest calls towards the server.
Here is my Gruntfile.js :
var proxySnippet = require('grunt-connect-proxy/lib/utils').proxyRequest;
module.exports = function(grunt) {
// Load Grunt tasks declared in the package.json file
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
// 1. Toutes les configurations vont ici:
grunt.initConfig({
pkg : grunt.file.readJSON('package.json'),
watch: {
all: {
files: 'webapp/*',
options: {
livereload: true,
}
},
},
express : {
all : {
options : {
bases : 'webapp',
port : 3000,
debug:true,
hostname : "0.0.0.0",
livereload : true,
middleware: function (connect, options) {
return [proxySnippet];
}
},
}
},
connect: {
proxies: [{
context: '/sis.cata/rest',
host: 'localhost',
port: 8080,
https: false,
changeOrigin: false,
xforward: false
}],
},
grunt.registerTask('develop', ['configureProxies:connect', 'express:all', 'watch' ]);};
Static files are served but calls to REST services are not proxied and blocks.
Any ideas ?
I have seen solutions with connect and proxy that works fine but never with livereload.
Thanks a lot.