I'm trying to use VueCLI and delete the output directory during serve, so that I can use this in my php files and determine whether to load dist assets or load via localhost:8080.
So in my vue.config.js I have:
module.exports = {
outputDir:'web',
configureWebpack: config => {
if (process.env.NODE_ENV !== 'production') {
console.log("its serve") // this logs
// here delete the outputDir
}
}
}
How do i delete a folder using the VueCLI since by default during serve my app is never deleted.
Use rimraf to remove directory.
const rimraf = require("rimraf");
module.exports = {
outputDir: 'web',
configureWebpack: config => {
if (process.env.NODE_ENV !== 'production') {
rimraf.sync(config.outputDir);
// rimraf.sync('web')
}
}
};
Alternative:
// package.json
"scripts": {
"serve": "rimraf web && vue-cli-service serve",
"build": "vue-cli-service build",
"lint": "vue-cli-service lint"
}
Related
I am running vue in production mode but i still get the warning of vue running in developer mode
the project is running fine and i can see that it running in production mode. but i am still getting the warning "You are running Vue in development mode.
Make sure to turn on production mode when deploying for production."
Below are my vue.config.js main.js and dockerfile
vue.config.js file
const webpack = require('webpack');
module.exports = {
devServer: {
host: "localhost",
port: 3123,
disableHostCheck: true,
},
publicPath: './',
configureWebpack: {
plugins: [
new webpack.DefinePlugin({
// allow access to process.env from within the vue app
'process.env': {
NODE_ENV: JSON.stringify(process.env.NODE_ENV)
}
}),
new webpack.ProvidePlugin({
jQuery: 'jquery',
'$': 'jquery',
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
]
},
chainWebpack: config => {
if (process.env.NODE_ENV === "production") {
config.plugin('define')
.tap(definitions => {
definitions[0] = Object.assign(definitions[0], {
'process.env': {
NODE_ENV: "'production-with-warns'"
}
});
return definitions
});
}
config.module
.rule('vue')
.use('vue-loader')
.tap(args => {
args.compilerOptions.whitespace = 'preserve'
})
},
lintOnSave: false,
transpileDependencies: ['vue2-datatable-component']
};
main.js file
import Vue from 'vue';
import Vuex from 'vuex';
import VueRouter from 'vue-router';
import 'bootstrap'
import 'bootstrap/dist/css/bootstrap.css'
import 'bootstrap3-dialog';
import 'bootstrap3-dialog/dist/css/bootstrap-dialog.css'
import 'bootstrap-select';
import 'bootstrap-select/dist/css/bootstrap-select.css'
import 'cropperjs'
import 'cropperjs/dist/cropper.css'
import 'flag-icon-css/css/flag-icon.css'
import 'eonasdan-bootstrap-datetimepicker'
import 'eonasdan-bootstrap-datetimepicker/build/css/bootstrap-datetimepicker.css'
import 'font-awesome/css/font-awesome.css'
import './useCompositionApi'
import App from './atar/App.vue';
import store from './store.js';
import routerConfig from './router.js';
import filters from './filters.js';
import resource from './resource.js';
import directives from './directives';
import mixins from './mixins';
import i18n from './i18n';
import * as uiv from 'uiv';
import Datatable from 'vue2-datatable-component';
import VueScrollTo from 'vue-scrollto';
import VueNotification from 'vue-notification';
import AsyncComputed from 'vue-async-computed';
import extensions from './extensions';
import windowConfiguration from './windowConfiguration.js';
import VueAutosize from 'vue-autosize';
import errorHandler from "./errorHandler.js";
import EventBusPlugin from "./plugin/EventBusPlugin";
import WindowResizePlugin from "./plugin/WindowResizePlugin";
import ScrollPlugin from "./plugin/ScrollPlugin";
import 'nodelist-foreach';
import WSSubscriber from "./plugin/WSSubscriber";
import validationConfiguration from "./veeValidateConfiguration";
import { AppInitializer } from "./AppInitializer";
Vue.use(Vuex);
const originalPush = VueRouter.prototype.push;
VueRouter.prototype.push = function push(location) {
return originalPush.call(this, location).catch(error => {
if (error.name !== "NavigationDuplicated") {
throw error;
}
});
}
Vue.use(VueRouter);
Vue.use(uiv);
Vue.use(VueAutosize);
Vue.use(Datatable);
Vue.use(VueScrollTo, {
duration: 500,
easing: "ease",
offset: 0,
cancelable: true,
onDone: false,
onCancel: false,
x: false,
y: true
});
Vue.use(VueNotification);
Vue.use(AsyncComputed);
Vue.use(EventBusPlugin);
Vue.use(WindowResizePlugin);
Vue.use(ScrollPlugin);
Vue.use(WSSubscriber);
new AppInitializer()
.addStep(() => resource.configure())
.addStep((ctx) => store.configure(ctx))
.addStep(() => filters.configure())
.addStep(() => mixins.configure())
.addStep(() => directives.configure())
.addStep(() => i18n.configure())
.addStep(() => windowConfiguration.configure())
.addStep(() => validationConfiguration.configure())
.addStep(() => {
Vue.config.productionTip = false;
if (process.env.NODE_ENV !== 'development') {
Vue.config.devtools = false;
}
})
.addStep((ctx) => {
ctx['router'] = new VueRouter(routerConfig);
})
.addStep((ctx) => {
new Vue({
el: '#app',
router: ctx['router'],
store: new Vuex.Store(ctx['store']),
render: h => h(App)
});
})
.addStep((ctx) => {
ctx['router'].afterEach((route) => {
document.title = route.meta.titleProducer(route);
});
})
.addStep(() => extensions.configureGlobal())
.addStep(() => errorHandler.configure())
.initialize();
docker file
# a.k.a. node:lts-alpine
FROM node:14.17.4-alpine as app-build-stage
RUN apk add git
WORKDIR /app
RUN npm i -g #vue/cli-service#4.5.15 #vue/cli-plugin-babel#4.5.15 #vue/cli-plugin-eslint#4.5.15 #vue/cli-plugin-typescript#4.5.15 #vue/cli-plugin-unit-jest#4.5.15 vue-template-compiler#2.6.14 typescript#4.6.3 autoprefixer#8.6.5 less-loader#4.1.0 less#3.9.0 webpack#4.46.0 babel-loader#8.2.3 #babel/core#7.16.0
COPY ./package*.json ./legal_notice.sh ./
RUN npm ci --production
RUN npm link #vue/cli-service #vue/cli-plugin-babel #vue/cli-plugin-eslint #vue/cli-plugin-typescript #vue/cli-plugin-unit-jest vue-template-compiler typescript autoprefixer less-loader less webpack babel-loader #babel/core
COPY . .
ENV NODE_ENV production
RUN export freeMem=$(free -m | grep Mem | awk '{print $4}') &&\
export minRequiredMem=2048 &&\
if [[ $freeMem -lt $minRequiredMem ]];\
then\
echo "[WARNING] Free memory ($freeMem MB) is less than the required limit ($minRequiredMem MB)." &&\
echo "[WARNING] Build is likely to fail due to insufficient memory.";\
fi;\
npm run build;\
if [[ ! -d "/app/dist" ]];\
then echo "The npm build process has failed and /app/dist folder is not found.";\
if [[ $freeMem -lt $minRequiredMem ]];\
then\
echo "Free memory : $freeMem MB";\
echo "Minimum memory required : $minRequiredMem MB";\
echo "The build has failed most likely due to insufficient memory.";\
exit 1;\
fi\
fi
WORKDIR /app
COPY ./docker/package*.json ./docker/server.js ./docker/apiinfo.js.template ./docker/entrypoint.sh /app/
RUN apk upgrade
RUN npm ci
# there are some overlay issues in the Jenkins so rm -rf ..../npm/ is not applicable
RUN find /usr/local/lib/node_modules/npm/ -type f -exec rm -f {} \;
COPY --from=app-build-stage /app/dist /app/static/
ENTRYPOINT ["./entrypoint.sh"]
Check your build command under package.json file, the development mode is set in the build command. like so...
"scripts": {
"serve": "vue-cli-service serve",
"devserve": "run-s build:dev watch",
"lint": "vue-cli-service lint",
"build": "vue-cli-service build --mode development",
}
I usually have two build commands configured, one to build for production and one for development
"scripts": {
"serve": "vue-cli-service serve",
"devserve": "run-s build:dev watch",
"lint": "vue-cli-service lint",
"build:dev": "vue-cli-service build --mode development",
"build:prod": "vue-cli-service build --mode production",
}
Make sure to run npm run build:prod for a production build and then deploy and the error should not appear.
I'm trying to build a moduler application with laravel-modules. I'm using Vue2 and InertiaJS on the front end and nWidart/laravel-modules on the backend.
In one of my modules I want to inlcude the vue-flowy package that no other module uses, and this module may not be installed on all installations of my app, so I don't want to load it in the root package.json file.
If I install the module in the primary package.json file, it works beautifully. But trying to install it in the module's package.json file will build in mix, but running the page gives me erors:
Modules_MyModule_Resources_js_Pages_Index_vue.js:660 [Vue warn]: $attrs is readonly.
Modules_MyModule_Resources_js_Pages_Index_vue.js:660 [Vue warn]: $listeners is readonly.
I'm assuming that the vue-flowy package is trying to build a secon Vue instance to run on, but I don't understand why or how to fix it.
/Modules/<myModule>/package.json
{
"private": true,
"scripts": {
"dev": "npm run development",
"development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --watch --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
"watch-poll": "npm run watch -- --watch-poll",
"hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
"prod": "npm run production",
"production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
},
"dependencies": {
"cross-env": "^7.0",
"laravel-mix": "^6.0.43",
"laravel-mix-merge-manifest": "^0.1.2",
"vue-flowy": "^0.3.1"
}
}
Vue Component Script section - this is pulled directly from the example on the vue-flowy website
<script>
import { VueFlowy, FlowChart } from 'vue-flowy';
export default {
components: { VueFlowy },
props: {
//
},
data() {
return {
chart: new FlowChart(),
}
},
mounted() {
const idea = this.chart.addElement('idea');
const A = this.chart.addElement("A", { label: "vscode" });
const B = this.chart.addElement("B", { label: "github" });
const C = this.chart.addElement("C", { label: "npm" });
idea.leadsTo(A).leadsTo(B);
A.leadsTo(C);
A.on("click", function() {
console.log("click!");
});
},
}
</script>
Main app.js file in /resources/js/app.js
import Vue from 'vue';
import { Link } from '#inertiajs/inertia-vue';
import BootstrapVue from 'bootstrap-vue';
////////////// Bunch of other stuff ///////////////
const el = document.getElementById('app');
InertiaProgress.init();
Vue.prototype.eventHub = new Vue();
new Vue({
render: h => h(App, {
props: {
initialPage: JSON.parse(el.dataset.page),
resolveComponent: (name) => {
// Determine if this is a primary page, or module page
let parts = name.split('::');
let module = false;
let page = false;
if(parts.length > 1)
{
// If it is a module page, load the module from the correct folder
module = parts[0];
page = parts[1];
if(module)
{
return import(`../../Modules/${module}/Resources/js/Pages/${page}.vue`)
.then(({ default: page }) =>
{
if (page.layout === undefined)
{
page.layout = Guest;
}
return page;
});
}
}
// primary page, load from the Pages folder
return import(`./Pages/${name}`)
.then(({ default: page }) =>
{
if (page.layout === undefined)
{
page.layout = Guest;
}
return page;
});
}
},
}),
}).$mount(el)
I try to bootstrap a simple app based on the following Vue3, Vite, Vitest
I also installed the vue 3 compatible version of vue test utils to test vue components.
I have an error trying to replicate the basic example in the docs :
import { mount } from "#vue/test-utils";
import { expect, test } from 'vitest'
// The component to test
const MessageComponent = {
template: "<p>{{ msg }}</p>",
props: ["msg"],
};
test("displays message", () => {
const wrapper = mount(MessageComponent, {
props: {
msg: "Hello world",
},
});
// Assert the rendered text of the component
expect(wrapper.text()).toContain("Hello world");
});
FAIL src/tests/hello-world.test.ts > displays message
ReferenceError: document is not defined
❯ Proxy.mount node_modules/#vue/test-utils/dist/vue-test-utils.cjs.js:7840:14
7838| addToDoNotStubComponents(component);
7839| registerStub({ source: originalComponent, stub: component });
7840| var el = document.createElement('div');
| ^
7841| if (options === null || options === void 0 ? void 0 : options.attachTo) {
7842| var to = void 0;
Re-running tests... [ src/tests/hello-world.test.ts ]
My package.json
{
"name": "vite-vue3-poc",
"version": "0.0.0",
"scripts": {
"serve": "vite preview",
"build": "vite build",
"coverage": "vitest --coverage",
"dev": "vite",
"preview": "vite preview",
"test": "vitest"
},
"dependencies": {
"#mdi/font": "5.9.55",
"prettier": "^2.5.1",
"roboto-fontface": "*",
"vue": "^3.2.25",
"vuetify": "^3.0.0-alpha.0",
"webfontloader": "^1.0.0"
},
"devDependencies": {
"#vitejs/plugin-vue": "^2.0.0",
"#vue/cli-plugin-babel": "5.0.0-beta.7",
"#vue/cli-service": "5.0.0-beta.7",
"#vue/test-utils": "^2.0.0-rc.18",
"#vuetify/vite-plugin": "^1.0.0-alpha.3",
"sass": "^1.38.0",
"sass-loader": "^10.0.0",
"vite": "^2.7.2",
"vitest": "^0.1.23",
"vue-cli-plugin-vuetify": "~2.4.5",
"vuetify-loader": "^2.0.0-alpha.0"
}
}
vite.config.js
import { defineConfig } from "vite";
import vue from "#vitejs/plugin-vue";
import vuetify from "#vuetify/vite-plugin";
import path from "path";
/// <reference types="vitest" />
// Configure Vitest (https://vitest.dev/config)
// https://vitejs.dev/config/
export default defineConfig({
test: {
/* for example, use global to avoid globals imports (describe, test, expect): */
// globals: true,
},
plugins: [
vue(),
// https://github.com/vuetifyjs/vuetify-loader/tree/next/packages/vite-plugin
vuetify({
autoImport: true,
}),
],
define: { "process.env": {} },
resolve: {
alias: {
"#": path.resolve(__dirname, "src"),
},
},
});
Finally fixed it by manually installing jsdom and declaring it in vite.config.ts
export default defineConfig({
test: {
globals: true,
environment: "jsdom",
},
...
}
Like others have pointed out, you need to set environment: 'jsdom' in vitest.config.ts. Alternatively, you could set environment: 'happy-dom'.
In the example provided by the Vitest documentation, they used to use happy-dom instead of jsdom. From what I gather, happy-dom is a faster alternative to jsdom. I'm using happy-dom in my project, and I'm happy with it! :)
EDIT: I changed my wording to reflect the fact that the Vitest example used to use happy-dom. As of this writing, it uses jsdom.
No need to install jsdom manually. By setting environment: "jsdom" in the test property, Vitest automatically asks you if you want to install it.
This config helped me
Your vite.config.ts
import { fileURLToPath, URL } from "node:url"
import { defineConfig } from "vite"
import type { UserConfig as VitestUserConfigInterface } from "vitest/config"
import vue from "#vitejs/plugin-vue"
const vitestConfig: VitestUserConfigInterface = {
test: {
globals: true,
environment: "jsdom",
},
}
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"#": fileURLToPath(new URL("./src", import.meta.url)),
},
},
test: vitestConfig.test,
})
I'm trying to deploy a sample project to Heroku. everything i try result in a 404. Here are my setup
server.js
const port = normalizePort(process.env.PORT || 9000);
...
const context = ({req}) => ({user: req.user && db.users.get(req.user.sub)});
const apolloServer = new ApolloServer({typeDefs, resolvers, context});
apolloServer.applyMiddleware({app, path: '/graphql'});
app.listen(port, () => console.info(`Server started on port ${port}`));
when I do heroku open and go to site.herokuapp.com/graphql i get a 404 and the same for site.herokuapp.com.
request.js
Also I Have a request.js that i use for importing the data from the graphql into my project like so:
import { ApolloClient, HttpLink, InMemoryCache, ApolloLink } from 'apollo-boost';
import gql from 'graphql-tag';
//The gql conver the string into a grapghql query that is required by apollo client
const endpointURL = '/graphql';
const client = new ApolloClient({
link: ApolloLink.from([
new HttpLink({uri: endpointURL})
]),
cache: new InMemoryCache()
});
I just can't seems to figure out how to deploy my project to heroku properly;
Project Structure
-root/
-client/
request.jsx
package.json
-server.js
-package.json
server
package.json
"scripts": {
"client": "cd client && yarn start",
"server": "nodemon server.js",
"build": "cd client && npm run build",
"dev": "concurrently --kill-others-on-fail \"yarn server\" \"yarn client\"",
"start": "node server.js",
"heroku-postbuild": "cd client && npm install && npm install --only=dev --no-shrinkwrap && npm run build"
},
client
package.json
"proxy": "http://localhost:9000",
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
Finally solved the issue. I was missing some packages like bodyParser and cors. I also forgot to point to the 'index.html'. Also I found out that you could add a Procfile to the root that would help heroku initiate npm start.
Updated server.js
const { ApolloServer, gql} = require('apollo-server-express');
const express = require('express');
const firebase = require('firebase/app');
require('firebase/firestore');
const bodyParser = require('body-parser');
const cors = require('cors');
const path = require('path');
if (process.env.NODE_ENV !== 'production') require('dotenv').config();
const config = {
apiKey: process.env.FIREBASE_API_KEY,
authDomain: process.env.AUTH_DOMAIN,
databaseURL: process.env.DATABASE_URL,
projectId: process.env.PROJECT_ID ,
storageBucket: process.env.STORAGE_BUCKET,
messagingSenderId: process.env.MESSAGING_SENDER_ID,
appId: process.env.APP_ID,
measurementId: process.env.MEASUREMENT_ID
};
firebase.initializeApp(config);
const firestore = firebase.firestore()
const normalizePort = port => parseFloat(port, 10);
const port = normalizePort(process.env.PORT || 9000);
const app = express();
app.use(cors());
const apolloServer = new ApolloServer({typeDefs, resolvers, context});
apolloServer.applyMiddleware({app, path: '/graphql'});
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.use(cors());
if (process.env.NODE_ENV === 'production') {
app.use(express.static(path.join(__dirname, 'client/build')));
app.get('*', function(req, res) {
res.sendFile(path.join(__dirname, 'client/build', 'index.html'));
});
}
app.listen(port, error => {
if (error) throw error;
console.log('Server running on port ' + port);
});
Add a Procfile to root then add the following line
web: npm start
I am trying to publish a basic React component to my npm registry and trying to reuse it. I think I am not following proper way to distribute my react component. Here's what I have:
This is the directory structure:
MyReactPOC
-> main.jsx
-> .npmrc
-> package.json
-> webpack.config.js
main.jsx
import React from 'react';
class MyComponent extends React.Component {
render() {
return (
<div>
<p>Hello from MyComponent!!</p>
</div>
);
}
}
export default MyComponent
package.json
{
"name": "#pankaj/my-component",
"version": "1.0.7",
"description": "POC for importing a component",
"main": "./dist/bundle.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"prepublish": "webpack --config webpack.config.js"
},
"repository": {
"type": "git",
"url": "my git repo"
},
"author": "Pankaj",
"license": "ISC",
"dependencies": {
"react": "~15.5.4",
"react-dom": "~15.5.4"
},
"devDependencies": {
"babel-cli": "~6.24.1",
"babel-core": "~6.24.1",
"babel-loader": "~6.4.1",
"babel-preset-es2015": "~6.24.1",
"babel-preset-react": "~6.24.1",
"webpack": "~2.4.1"
}
}
webpack.config.js
var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './main.jsx',
output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' },
module: {
loaders: [
{
test: /.jsx?$/,
loader: 'babel-loader',
exclude: /node_modules/,
query: {
presets: ['es2015', 'react']
}
}
]
},
};
I import the module in another project using import MyComponent from '#pankaj/my-component'.
When I use this component like
I get the following error:
React.createElement: type is invalid -- expected a string (for
built-in components) or a class/function (for composite components)
but got: object. You likely forgot to export your component from the
file it's defined in.
Please help me understand the right way to distribute the react components so that they can be used by other projects within my org.
Here is how I use this component:
ComponentUse.js
import React from 'react';
import ReactDOM from 'react-dom';
import MyComponent from '#pankaj/my-component';
ReactDOM.render(
<MyComponent/>,
document.getElementById('root')
);
I have an index.html that has the 'root' div.
Every react component needs a return statement. Add a return statement in your render function and it should work.
...
render() {
return (<div>...</div>)
}
You cannot directly render to the Dom from your react component, instead return it so that react can work with it.
In webpack, specify your output file as a library using output.library https://webpack.js.org/concepts/output/#output-library
I wrote a full Medium story because I had the same issue as you and there is no information about it.
Check it out: https://medium.com/#BrodaNoel/how-to-create-a-react-component-and-publish-it-in-npm-668ad7d363ce
The main fix is to add libraryTarget: 'umd' in the webpack.config.js file
If you export with es6 syntax with babel, your component will be in MyComponent.default namespace. To avoid this you should install:
npm i --save-dev babel-plugin-add-module-exports in your .babelrc?
and add it to the babel conf:
{
"presets": [ "es2015", "react"],
"plugins": ["add-module-exports"]
}