Configure webpack for vue such that backend express server is in ECMA2016 - express

I wrote an app using the webpack-boilerplate for vue. The backend handling GET and POST requests is an express-server. IDE is visual studio code.
This is what I did:
$ vue init webpack app
$ cd app
$ npm install
$ npm install axios express body-parser node-sass sass-loader
$ npm install --save-dev concurrently nodemon
app/express/app.js looks like:
//import express from express
var express = require('express')
var app = express()
// sets port 8080 to default or unless otherwise specified in the environment
app.set('port', process.env.PORT || 8080)
var bodyParser = require('body-parser')
app.use(bodyParser.json())
app.use(express.static(`${__dirname}/../dist/`))
// Test: curl -X POST -H "Content-Type: application/json" -d '{"path": "bla/blub.txt"}' http://localhost:8081/api/save
app.post('/api/save', function (req, res) {
response = {
msg: 'okay',
data: Math.floor(Math.random() * 10)
};
res.end(JSON.stringify(response))
})
var server = app.listen(app.get('port'), function () {
var host = server.address().address
var port = server.address().port
console.log("Example app listening at http://%s:%s", host, port)
})
I modified the boilerplate code generated by vue init webpack such that app/components/HelloWorld.vue is:
<template>
<div>
<h1>{{ msg }}</h1>
</div>
</template>
<script>
import Axios from 'axios'
const baseUrl = "http://127.0.0.1:8080/api"
export default {
name: 'HelloWorld',
data () {
return {
msg: 'Welcome to Your Vue.js App'
}
},
async created() {
this.msg = await Axios.post(`${baseUrl}/save`, {"path": "bla/blub.txt"})
.then(response => new Promise(resolve => {
let msg = response.data.msg
resolve(msg)
}))
.catch(error => {
console.log(error)
Promise.reject(error)
})
}
}
</script>
<style lang="scss" scoped>
h1 {
font-weight: normal;
}
</style>
To start development in one command (npm start go) and allow hot reloading, I changed app/package.json (don't know where I copied that from):
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"apiserver": "PORT=8081 nodemon express/app.js",
"go": "concurrently --kill-others \"npm run dev\" \"npm run apiserver\"",
"start": "npm run dev",
"build": "node build/build.js"
},
To start the dev version of the app, I ran:
$ npm run dev # webpack-dev-server starts on port 8080, express on 8081
To avoid CORS-problems, webpack can be configured to proxy express requests. Change app/config/index.js:
proxyTable: {
'/api':{
target: 'http://localhost:8081',
changeOrigin: true,
}
},
One can now run npm run dev from app/ again, everything works fine.
Hence, over to production mode. I run
$ npm run build
$ node express/app.js
Everything runs fine.
(Over time, I added answers found by myself into this question... The original question was: "Configure webpack for vue frontend and express backend (scenario both production and development)")
My question is now:
How to change webpack babel setup such that the node-run file app.js uses ECMA2016 (such that import express from express can be used instead of require ...)?
Thanks for any help!

Related

npm run multiple scripts (node app.js & gulp watch)

I would like to run app.js & gulp watch in a single command, however when I run npm run watch, the terminal stop on listen to port 3000, my gulp watch are not executed.
Below are my files:
packaga.json
"scripts": {
"watch": "node app.js & gulp watch"
}
app.js
var express = require('express');
var app = express();
app.use(express.static(__dirname + '/build'));
app.listen(3000);
console.log('listen to port 3000');
gulpfile.js
gulp.task('watch', function(){
gulp.watch('./src/*.scss', gulp.series(['styles', 'css']));
})
"node app.js && gulp watch":
This runs the express server, then the gulp command. As long as your server is running the gulp won't be executed I guess.
Maybe take a look at this page:
Starting an express server from within gulp

How to migrate from node-sass to sass (dart sass) in an express app

With LibSass deprecated, I see that I should replace the node-sass library with sass. In an express app, previously, you would use the node-sass-middleware and node-sass like so:
const express = require('express');
const sassMiddleware = require('node-sass-middleware');
const path = require('path');
const app = express();
app.use(sassMiddleware({
/* Options */
src: __dirname,
dest: path.join(__dirname, 'public'),
debug: true,
outputStyle: 'compressed',
prefix: '/prefix' href="prefix/style.css"/>
}));
app.use('/public', express.static(path.join(__dirname, 'public')));
The only indication I found about how to use the sass module with express is this article. This method does not use a middleware but instead runs the sass module via a script (configured inside the packages.json file). Here is the relevant part of the article:
"scripts": {
"start": "node .",
"dev": "nodemon . & npm run scss",
"scss": "sass --watch src/scss/main.scss public/styles/main.css"
},
But my confidence in this article is low. For starters, it seems to be compiling sass only in development (the "start" script does not use the "scss" script). Also, this method does not use a middleware.
So, I guess I have 2 questions:
is there a way to use a middleware (like the old node-sass-middleware) to use the sass module with express? (It would be easier to update my code and I'm lazy...)
If not, is the example in the article the correct way to use sass with express?
I didn't want to rely on remembering to run a script manually (I would definitely forget to do it) and combining scripts with "&" (or even "&&") like in the article was not working so well for me.
I wanted to use code to launch the script, so what I did is just compile my CSS synchronously when the server starts.
Here is my code:
app.js
const express = require('express');
const path = require('path');
const { compileCss } = require('./compileCss');
const app = express();
const sassOptions = {
src: path.join(__dirname, 'public'),
dest: path.join(__dirname, 'public')
};
compileCss(sassOptions);
app.use('/public', express.static(path.join(__dirname, 'public')));
# ... rest of app.js code
compileCss.js
const sass = require('sass');
const { readdirSync , writeFileSync} = require('fs');
const path = require('path');
const compileCss = ({src, dest, ext=[".sass", ".scss"]}) => {
const srcFiles = readdirSync(src, {withFileTypes: true}).filter(dirent => dirent.isFile() && ext.includes(path.extname(dirent.name)));
for(const file of srcFiles) {
const srcFilePath = path.join(src, file.name);
const baseName = path.basename(file.name, path.extname(file.name));
const cssName = baseName + '.css';
const destFilePath = path.join(dest, cssName);
const result = sass.compile(srcFilePath);
writeFileSync(destFilePath, result.css, 'utf-8');
}
}
module.exports = { compileCss }
I haven't tested it yet, but I think if you download dart-sass-middleware and require it instead of node-sass-middleware then it should work.
This is what I ran to install it:
npm install dart-sass-middleware
More details on dart-sass-middleware can be found at https://www.npmjs.com/package/dart-sass-middleware
Let me know if it works!
Instead of node-sass-middleware you can use express-dart-sass.
Here is their repo.

A way to run vite dev on remote server (like Laravel Mix)

I've switched from Laravel Mix to Vite, and am trying to accomplish same thing "npm run watch" does for Laravel Mix. Caveat: our staging servers are not local (i.e. staging.app-domain-name.com). If I run npm run dev with Vite it revs up the "dev" server that's supposed to be at http://ip:3000, but that obviously does not work. Aside from not having an active watcher, I can't get the dev to be used with Vue Devtools plugin (since vite only can spit out prod on server).
My vite.config.js:
const { resolve } = require('path');
import vue from '#vitejs/plugin-vue';
export default ({ command }) => ({
base: command === 'serve' ? '' : '/dist/',
publicDir: 'fake_dir_so_nothing_gets_copied',
build: {
manifest: true,
outDir: resolve(__dirname, 'public/dist'),
rollupOptions: {
input: 'resources/js/app.js',
},
},
server: {
host: true,
port: '8080',
hot: true
},
plugins: [vue()],
resolve: {
alias: {
'#': resolve('./resources/js'),
},
},
});
My app.js
import "./bootstrap";
import '../css/app.css';
import { createApp, h } from 'vue';
import { App as InertiaApp, plugin as InertiaPlugin } from '#inertiajs/inertia-vue3';
import { InertiaProgress } from '#inertiajs/progress';
let asyncViews = () => {
return import.meta.glob('./Pages/**/*.vue');
}
const el = document.getElementById('app');
createApp({
render: () =>
h(InertiaApp, {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: async name => {
if (import.meta.env.DEV) {
return (await import(`./Pages/${name}.vue`)).default;
} else {
let pages = asyncViews();
const importPage = pages[`./Pages/${name}.vue`];
return importPage().then(module => module.default);
}
}
}),
})
.mixin({ methods: { route } })
.use(InertiaPlugin)
.mount(el);
And package.json scripts:
"scripts": {
"predev": "printf \"dev\" > public/hot",
"dev": "vite",
"preprod": "printf \"prod\" > public/hot",
"prod": "vite build"
}
Desired outcome to generate dev bundle on a remote server by running
npm run dev
Currently it tries to create localhost dev. I assume something in vite.config.js needs to be set to get that done. I've gone over the docs but could not find anything clear enough.
To tell Vite to listen also on network interface simply add --host parameter to dev script:
"scripts": {
"dev": "vite --host",
"prod": "vite build"
},
It gives me an result like this:
vite v2.5.10 dev server running at:
> Local: http://localhost:3000/
> Network: http://x.y.x.z:3000/ <-- server public IP
> Network: http://10.10.10.1:3000/ <-- server local IP via VPN
ready in 330ms.
But this was not solution. I had a problem with CORS. I resolved it in another way. It depends on web server. I use nGinx and I set reverse proxy to listen on port 3000.
server {
listen x.y.x.z:3000 ssl; ### Server public IP address
server_name dev.example.com;
location / {
proxy_pass https://127.0.0.1:3000/; ### https: is Important
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection upgrade;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $remote_addr;
}
# SSL config
ssl_certificate /srv/certs/example.com/fullchain.cer;
ssl_certificate_key /srv/certs/example.com/example.com.key;
include ssl_config;
}
Ii is also important to listen only on public IP address due to not conflict with vite on same port. Vite default listen only on localhost. Reload nGinx
sudo nginx -t
sudo systemctl reload nginx
In package.json I put --https atribute
{
"private": true,
"scripts": {
"dev": "vite --https",
"prod": "vite build"
},
"devDependencies": {
"postcss": "^8.1.14",
"vite": "^2.5.10"
}
}
And that's it. Now I am able run
npm run dev
Finnally I put scripts to my layout blade end Vite start works.
<script type="module" src="https://dev.example.com:3000/#vite/client"></script>
<script type="module" src="https://dev.example.com:3000/resources/js/app.js"></script>
Setup nginx to proxy websocket
https://www.nginx.com/blog/websocket-nginx/
Sebastyan's guide to setup Vite with Laravel
https://sebastiandedeyne.com/vite-with-laravel
Adding this server part of this config to my config in vite.config.js file fixed things for me.
export default defineConfig({
server: {
hmr: {
host: 'localhost',
}
}
});
Except you may want to change the host part from localhost to your server's IP address.
Then do npm run dev -- --host as others have mentioned.
I copy pasted this answer from here without reading anything else about it or why it works.
Adding --host separated by -- worked in my case - no changes in config files needed this way:
npm run dev -- --host
Try this:
CMD [ "npm", "run", "dev", "--", "--host"]
It worked for me but the app keeps reloading
Adding the arguments "--" "--host" to my Docker file did the trick.
like so:
CMD [ "npm", "run", "dev", "--", "--host"]
this allows me to start the server in dev mode and to reach it from my host.
{
"name": "zustand",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"cmd": "cmd /k npm run dev -- --host",
"host": "vite --host",
"dev": "vite",
"build": "tsc && vite build",
"preview": "vite preview"
},
"dependencies": {
"#tanstack/react-query": "^4.20.9",
"axios": "^1.2.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"zustand": "^4.2.0"
},
"devDependencies": {
"#types/react": "^18.0.26",
"#types/react-dom": "^18.0.10",
"#vitejs/plugin-react": "^3.0.1",
"typescript": "^4.9.4",
"vite": "^4.0.4"
}
}
---
vite --host
VITE v4.0.4 ready in 623 ms
➜ Local: http://localhost:5173/
➜ Network: http://172.19.80.1:5173/
➜ Network: http://192.168.100.14:5173/
➜ press h to show help
para que funcione "vite --host", debe estar instalado globalmente.
Ej: npm install vite -g

Nuxt How to set baseURL in dev or production

This seems like a simple Nuxt question, but I just can't figure it out.
When running "NPM run dev" I want to set the Axios baseURL to "localhost/api" and when running from the dist folder after "NPM run generate" I want the baseURL to be "/api".
Is there a simple solution?
This is the way to do it through the nuxt.config.js:
let development = process.env.NODE_ENV !== 'production'
module.exports = {
axios: {
baseURL: development ? 'http://localhost:3001/api' : 'https://domain/api'
},
modules: [
'#nuxtjs/axios'
],
}
As you can see, you should specify full URL of your backend, including domain (except SPA-only mode).
And don't forget to install #nuxtjs/axios as dependency to try the example.
you can also set api from outside (eg package.json scripts) by env variable
my package.json fragment (there is additional complexity when browser uses different
api url then server side rendering, still all is supported by Nuxt itself with variables API_URL_BROWSER and API_URL)
"scripts": {
"dev-prodapi": "API_URL=https://kairly.com/api nuxt",
"dev": "API_URL=http://localhost:8000/api nuxt",
"dev-spa-prodapi": "API_URL=https://kairly.com/api nuxt --spa",
"dev-spa": "API_URL=http://localhost:8000/api nuxt --spa",
"build": "API_URL_BROWSER=https://kairly.com/api API_URL=https://internal-apihost/api/ nuxt build --modern=server",
"start": "API_URL_BROWSER=https://kairly.com/api API_URL=https://internal-apihost/api/ nuxt start --modern=server",
and using no axios section in nuxt config at all.
In Nuxt 3 we can use a .env file. Here's the doc.
# .env
API_URL=http://localhost:8080/api
// nuxt.config
export default defineNuxtConfig({
runtimeConfig: {
// Private keys are only available on the server
apiSecret: '123',
// Public keys that are exposed to the client
public: {
apiUrl: process.env.API_URL
}
}
})
// MyComponent.vue
<script setup>
const config = useRuntimeConfig()
console.log(config.public.apiUrl)
</script>

Watch and rerun Jest JS tests

The Jest documentation suggests using npm test to execute tests.
Is there a way of watching your source and tests to rerun Jest tests automatically when relevant files have been changed?
Thanks to Erin Stanfill for pointing out, Jest already has support for automatically re-running. The better configuration for package.json would be
{
"scripts": {
"test": "jest"
}
}
To turn on the watch mode, just use
$ npm run test -- --watch
Or
$ yarn run test --watch
If you have npm test configured, you can just run npm test -- --watch.
As a complement suggestion you can add "--watchAll"
into your package.json file like this:
"scripts": {
"test": "jest --watchAll"
},
Each time you run npm test, the watch mode will be enable by default.
For more info npm CLI docs
Start you tests in watch mode.
jest --watch fileName.test.js
As per documentation
Run tests that match this spec name (match against the name in describe or test, basically).
jest -t name-of-spec
// or in watch mode
jest --watch -t="TestName"
This example shows how to use gulp to run your Jest tests using jest-cli, as well as a tdd gulp task to watch files and rerun Jest tests when a file changes:
var gulp = require('gulp');
var jest = require('jest-cli');
var jestConfig = {
rootDir: 'source'
};
gulp.task('test', function(done) {
jest.runCLI({ config : jestConfig }, ".", function() {
done();
});
});
gulp.task('tdd', function(done) {
gulp.watch([ jestConfig.rootDir + "/**/*.js" ], [ 'test' ]);
});
gulp.task('default', function() {
// place code for your default task here
});
install a couple of Grunt packages:
npm install grunt-contrib-watch grunt-exec --save-dev
make a Gruntfile.js with the following:
module.exports = function(grunt) {
grunt.initConfig({
exec: {
jest: 'node node_modules/jest-cli/bin/jest'
},
watch: {
files: ['**/*.js'],
tasks: ['exec:jest']
}
});
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-exec');
}
then simply run:
grunt watch
If you want to run a single file in watch mode:
yarn run test --watch FileName.test.jsx
I personally use the npm package jest-watch-typeahead.
You need to do 3 steps:
Install npm packege:
npm install --save-dev jest jest-watch-typeahead
Add to jest.config.js next code:
module.exports = {
watchPlugins: [
'jest-watch-typeahead/filename',
'jest-watch-typeahead/testname',
],
};
Run Jest in watch mode
yarn jest --watch