I want to build two separate vue apps that will be served on two different routes in an express application: a ‘public’ vue app and an ‘admin’ vue app. These two apps have their own router and store but they share a lot of custom components.
How can I edit the default webpack template to make it output two separate bundles based of my two different entry points (‘public’ and ‘admin’)?
The goal would be to end up with a setup more or less like this:
my-app/
+- ...
+- dist/
| +- admin/ Admin bundle and files
| +- public/ Public bundle and files
+- src/
| +- components/ Shared components
| +- admin/ Entry point, router, store... for the admin app
| +- public/ Entry point, router, store... for the public app
+- ...
Must by available 2 dev servers http://localhost:8080/admin and http://localhost:8080/public
Each project must be in own folder in dist, and own public
What i have today:
created file vue.config.js in root directory
With:
module.exports = {
// tweak internal webpack configuration.
// see https://github.com/vuejs/vue-cli/blob/dev/docs/webpack.md
chainWebpack: config => {
// If you wish to remove the standard entry point
config.entryPoints.delete('app')
// then add your own
config.entry('admin')
.add('./src/admin/index.js')
.end()
.entry('public')
.add('./src/public/index.js')
.end()
}
}
Assuming you need completely separate builds, with some shared scripts guided by your entries, you can add separate build commands.
In your package.json "scripts" section:
"scripts": {
"build:admin": "vue-cli-service build --dest dist/admin src/admin/index.js,
"build:public": "vue-cli-service build --dest dist/public src/public/index.js
}
For admin builds, you may run:
npm run build:admin
and for public builds:
npm run build:public
For more information, view the build target docs.
I am also very interested by this matter.
Maybe we can solve this issue with subpages :
https://cli.vuejs.org/config/#pages :
"Build the app in multi-page mode. Each "page" should have a corresponding JavaScript entry file. The value should be an object where the key is the name of the entry, and the value is either:"
module.exports = {
pages: {
index: {
// entry for the *public* page
entry: 'src/index/main.js',
// the source template
template: 'public/index.html',
// output as dist/index.html
filename: 'index.html'
},
// an admin subpage
// when using the entry-only string format,
// template is inferred to be `public/subpage.html`
// and falls back to `public/index.html` if not found.
// Output filename is inferred to be `admin.html`.
admin: 'src/admin/main.js'
}
}
Building on the other answers here, I've found it's possible to specify the build output directory in vue.config.js rather than having to do that in the command line. So then combining that with the use of the VUE_CLI_SERVICE_CONFIG_PATH environment variable makes things a lot simpler - no need for it to copy/delete config files each time you build.
You do have to specify the full paths to the Vue config files though. This works even on Windows, but only from a Linux-type terminal (e.g. I tested it from Git Bash installed by Git for Windows and it worked fine, but doesn't work from the normal Windows Command Prompt, as I couldn't find any way of setting the environment variable in the npm script which worked when run from there)
https://gist.github.com/EdwardMillen/0c417747cd8ce64b8ba550bdfa582cf5
It is also possible to have multiple vue.config.js configs and switch them over using the VUE_CLI_SERVICE_CONFIG_PATH environment variable.
For example, we can have a default vue.config.js and an additional vue.public.config.js and run the build like this:
# Build using vue.config.public.js
# Note: using real path here, it didn't work with relative path
CONF=`realpath vue.config.public.js`
VUE_CLI_SERVICE_CONFIG_PATH=$CONF npm run build
# Build using default vue.config.js
npm run build
Where npm run build is defined in package.json as vue-cli-service build:
"scripts": {
"build": "vue-cli-service build"
}
Note: I didn't find any mention on VUE_CLI_SERVICE_CONFIG_PATH in the documentation, found it looking at the source code.
Related
I'm having trouble configuring vite.config.js so that I can have both my Vue app and a service worker file live in the dist folder. My service worker was working with webpack previously but I've just upgraded to Vite and I'm having trouble configuring the build. My goal is to have my dist folder look like:
dist
|- index.html
|- sw.js
|- assets
|- app.[hash].js
I tried various different configurations but none of them have worked:
An approach that is recommended by Workbox. It seems like this doesn't work because of what is mentioned in this comment.
After reading that comment I tried to separate the logic out into a separate file (vite-sw.config.js) and running vite build -c vite-sw.config.js. This successfully generated the file I wanted but I couldn't figure out how to get that file mixed in with the original build. Is there a way to combine vite build and vite build -c vite-sw.config.js so that they both output to the same dist directory without overriding each other?
I found this alternative approach which successfully created the folder structure I wanted in dist but I was unable to adjust the format of the service worker file so I got Cannot use import statement outside a module (at sw.js:1:1) in the browser. Is there some way to use this method and somehow configure the format of the service worker file?
Any other ideas? I've been pretty stuck on this for a while. Thanks!
Try changing your configuration like this:
export default defineConfig({
build: {
rollupOptions: {
output:
{
format: 'es',
strict: false,
entryFileNames: "[name].js",
dir: 'dist/'
}
}
},
.
.
.
});
Using NPM Workspaces, I'm sharing one package (components) with others (webapp1 and webapp2). Something like this:
root
apps
webapp1
webapp2
packages
components
Everything is working well, but everything inside components, include source code in the src folder is being shared. Since components' compiled output folder is dist, I'd like to only share that folder. This is how it looks in the root node_modules:
The problem is that when I need to import in webapp1 or webapp2, my import path has to include the dist folder. Here's the intellisense that I get from VS Code:
And this is how I import in webapp1 and webapp2:
import Center from '#mycompany/components/dist/Center'
While everything works, how can I set up my NPM Workspaces so that only the contents of the dist folder is shared in its root?
I've tried NPM's files and .npmignore inside the components folder to ignore everything except for the dist folder, but that doesn't seem to work. The main property in package.json for components is also set to point to dist/index.js:
"main": "dist/index.js"
Interestingly, if I want to import dist/index.js file, I can do it without dist:
import foo from '#mycompany/components'
...however, importing anything other than dist/index.js requires dist to be included in the path.
You should treat the packages folder as a collection of dist folders in your use case.
In this scenario, you would move your packages/components/src folder somewhere else in your project and then build to packages/components instead of packages/components/dist
root
apps
webapp1
webapp2
packages
components
src
components
I have a similar setup in this tooling monorepo I created
An alternative to #nicksaroba's approach, if you don't want to restructure your project layout, you can just setup an alias:
// apps/webapp/webpack.config.js
module.exports = {
// ...
resolve: {
alias: {
"components": "#mycompany/components/dist/"
}
},
// ...
};
While I clearly am no webpack expert, I usually figure/find out what I need to modify in order to achieve what I need. However, I lost more than a day on this one, even though it seems fairly simple:
I want to add an index.html to the build, after building, by copy-ing it from a folder.
I tried adding this to configureWebpack, in vue.config.js:
plugins: [
new CopyPlugin([{
from: 'deploy',
to: '/',
force: true,
copyUnmodified: true
}])
]
(the only file in deploy folder is this index.html).
I also tried various versions of chainWebpack, mostly picked from github discussions, trying to tap into plugins like html, move-index and copy. However, most of what I found on github breaks the build for me.
Not even simple attempts, where I just try to tap and console don't seem to work:
chainWebpack: config => {
config
.plugin('html')
.tap(args => {
console.log(args);
return args;
});
},
outputs:
Building for production as library (commonjs,umd,umd-min)...[]
ERROR TypeError: Cannot read property '__expression' of undefined`
...
at module.exports.toConfig (D:\sgn\www\_g\berwow\BERWoW\Client\RecommenderV2\node_modules\webpack-chain\src\Config.js:129:40)
What I figured out so far:
CopyPlugin either doesn't work or it has an exception for .html files.
There're are at least two plugins: (move-index & html) which probably interfere with my copy. I haven't figure out how to push my change to the back of the queue.
I also tried with a test.html and I also tried placing a different extension on my file .txt and overriding it when copying it, back into .html. Most times I end up with errors.
Is there a relatively straight forward way to tap into vue-cli-serve's build command and simply copy an index.html to the folder?
The build command I'm using is:
vue-cli-service build --target lib --name SomeName --inline-css --inline-vue src/main.ts
Please note it's a --target lib build, which doesn't output an index.html into the dist folder, but a demo.html. So I'd advise testing any solution against a --target lib build, as it clearly has a different output than normal builds.
Here's the output of vue inspect: https://jsfiddle.net/websiter/rkh5ecvd/embedded/js/dark/#JavaScript
and here's the current contents of my vue.config.js: https://jsfiddle.net/websiter/fou3y4zc/embedded/js/dark/#JavaScript , where configWebpack and chainWebpack are attempts at addressing/peeking into the above issue.
I'm using #vue/cli 4.2.3 and vue 2.6.11 with webpack 4.42.1
I figured out a way around it, by simply running npm i copyfiles -D and adding this bit to the build script:
&& copyfiles -f ./deploy/* dist/Recommender
It's not a proper answer to the problem, it's a way around it. But it works :).
Still interested in how this could be chained to the webpack build script properly.
I know this is an old issue, but I figured I'd add some more details for anyone still having issues with this in Vue 3.
I was able to achieve a similar output with vue 3.0.0, #vue/cli-service 4.5.0, webpack 4.46.0 and copy-webpack-plugin 6.4.1 using the following configs:
vue.config.js
const CopyPlugin = require("copy-webpack-plugin");
/**
* #type {import('#vue/cli-service').ProjectOptions}
*/
module.exports = {
chainWebpack: (config) => {
// Disable HTML Generation.
config.plugins.delete("html");
config.plugins.delete("preload");
config.plugins.delete("prefetch");
// Copy all contents of the "static" src directory
// to the destination's root.
config.plugin("copy").use(CopyPlugin, [
{
patterns: [{ from: "./static", to: "./" }],
},
]);
},
};
npm script:
vue-cli-service build --target lib --inline-vue --name app src/main.js
Note: the "inline-vue" argument forces embedding Vue into the bundle (see https://cli.vuejs.org/guide/build-targets.html#library).
I'm trying to build a library (mostly some .vue components) to reuse in different projects (no public npm) with vue-cli-service. Apparently everything its already setup, and I can confirm that the build is fine (js, and css). However, I'm unable to use it in a separate project as an external module because it uses the spread operator (and probably more ES20XX features no yet parsed).
Module parse failed: Unexpected token (2683:8)
You may need an appropriate loader to handle this file type.
| params() {
| const queryParams = {
| ...this.filters,
| ...this.sorting,
| ...this.config.params,
This is the standard command I'm using to build the library
vue-cli-service build --target lib --name [mylibname] ./src/components/index.js
By default the bundle should be already polyfilled but it seems to me that it's not the case.
I've read that I might change the webpack configuration on the project I'm using into, but I'm against parsing the whole node_module folder and also I would love to just have the simplest workflow possible (like import a module and its css).
So my question is, how to polyfill my bundle to be perfectly usable in no matter what Vue project without any hassle ?
Ok, it seems that reinitializing the project with vue-cli without typescript and with separated configuration files instead of into package.json was a good idea, as now is transpiled as needed.
var queryParams = _objectSpread({}, this.filters, {}, this.sorting, {}, this.config.params);
Unfortunately the hidden configuration of vue-cli webpack can't help to see what has changed.
I am building a react-native app which embeds a WebView in order to host some non-native react components. I have a small html file which is the source for the WebView and lives in a sub-folder of android/app/src/main/assets, which I understand is where it needs to be for the build to copy it to the apk, though I think I will need another copy in another location for IOS. So far so good...this much works.
Now, the htm file needs to pull in the regular react components from code in an npm module. It contains a script tag whose src needs to reference a file which is available in a subdirectory of node_modules. I don't know of any url I can put in the src that will reference the file direct from node_modules and get it copied to the apk. The simple solution is to manually copy the file into the same subfolder of android/app/src/main/assets and simply use its name as the src. This also works, though there may be a better way.
Problem: how can I automate copying the file from node_modules to assets?
(Ideally, a solution would also work for IOS, though at this point I'd be glad to have an android-only one.)
I explored rnpm and react-native link. Documentation I can find is very inadequate, but it appears this mechanism can only be used for fonts.
I explored adding a copy command to the start script in package.json, like this:
"scripts": {
"start": "copy/Y node_modules/X/Ybundle.js android/app/src/main/assets/X/Ybundle.js & node node_modules/react-native/local-cli/cli.js start"
},
but the copy did not happen when I ran react-native start-android.
I am wondering whether something could be added to the react-native project's gradle script, but cannot find any documentation on how this is used in the react native build process.
The best solution I've found so far is to add some scripts to package.json:
"scripts": {
"copyAssets": "node -e \"fs.copyFileSync('./node_modules/bloom-player-react/output/bloomPlayerControlBundle.js','./android/app/src/main/assets/bloom-player/bloomPlayerControlBundle.js')\"",
"start-android": "npm run copyAssets && react-native run-android",
...
}
Then when I npm run start-android, first the copy happens, and then the normal android startup.
I answered very same question in here with same answer: https://stackoverflow.com/a/72191579/7376041
For Android, you can run a custom Gradle task that able to will handle copy your assets in build time.
Create a Gradle file in your module's root, like below:
(I presume your module name is react-native-my-awesome-module and your HTML files is under www folder in module's root.)
awesome.gradle:
/**
* Register HTML asset source folder
*/
android.sourceSets.main.assets.srcDirs += file("$buildDir/intermediates/ReactNativeMyAwesomeModule")
/**
* Task to copy HTML files
*/
afterEvaluate {
def targetDir = "../../node_modules/react-native-my-awesome-module/www";
def fileNames = [ "*.html" ];
def htmlCopyTask = tasks.create(
name: "copyReactNativeMyAwesomeModuleAssets",
type: Copy) {
description = "copy react native my awesome module assets."
into "$buildDir/intermediates/ReactNativeMyAwesomeModule/www"
fileNames.each { fileName ->
from(targetDir) {
include(fileName)
}
}
}
android.applicationVariants.all { def variant ->
def targetName = variant.name.capitalize()
def generateAssetsTask = tasks.findByName("generate${targetName}Assets")
generateAssetsTask.dependsOn(htmlCopyTask)
}
}
After installing the module, put the below line in your project's android/app/build.gradle file:
apply from: file("../../node_modules/react-native-my-awesome-module/awesome.gradle");
When you build your app, your assets under www folder will be copied from your module. You can access your resources in your app like below :
<WebView
source={{uri: 'file:///android_asset/www/index.html'}}
/>