If you don’t have node installed there are several ways to do it. One way is to use Node Version Manager (nvm).
curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.0/install.sh | bash
Install the latest Long Term Support (LTS) version of node (currently 10.15.1).
nvm install node
If you dont have Vue cli installed (Node must already be installed).
npm install --global @vue/cli
Use the appropriate package manager for your OS. These instructions were tested with maven version 3.6.
Use the appropriate package manager for your OS. These instructions were tested with gradle 5.2.
Replace {component-name}
with the desired name for the component.
vue create {component-name} --default
Install dependencies for legacy browser support in the newly generated app.
cd {component-name}
npm install --save-dev @babel/{cli,plugin-transform-runtime,preset-env}
Note: whenever you modify dependencies in the Vue application you must
re-run the npm install
command above.
In the root directory, create a gradle.properties file, with the following content:
group=org.webjars.npm
This is the standard GroupId for NPM package WebJars.
Create a build.gradle file. Here is a simple sample for -SNAPSHOT
versions:
apply plugin: 'java'
apply plugin: 'maven'
def jsonFile = file("${projectDir}/package.json")
def parsedJson = new groovy.json.JsonSlurper().parseText(jsonFile.text)
project.version = parsedJson.version + '-SNAPSHOT'
/* remove '-SNAPSHOT' for release version */
jar {
archiveBaseName = project.name
from '.'
into "META-INF/resources/webjars/${project.name}/${project.version}"
include 'META-INF'
include 'dist/*'
exclude "dist/demo.html"
exclude "dist/${project.name}.js"
exclude "dist/${project.name}.js.map"
exclude "dist/${project.name}.min.js.map"
}
This gets the project version from package.json, appends -SNAPSHOT
to
it, creates a .jar file with the recommended paths for
contributing WebJars
(META-INF/resources/webjars/${name}/${version}
), and includes just the
{project-name}.min.js
file generated by Vue, to keep the WebJar as
small as possible. It excludes non-essential files. You can delete
+ '-SNAPSHOT'
for a release version. Modify build.gradle to include
additional files you may need.
This works for building and publishing to the local Maven repository on
your computer with ./gradlew build
and ./gradlew install
. To publish
to a remote repository and for details on creating a build.gradle file, or
if you have problems, see
C. Creating build.gradle files in the
Appendix.
Run this:
gradle wrapper --gradle-version=5.1.1
Note: now that the project has a build.gradle file and a Gradle wrapper, an IDE like IntelliJ IDEA will recognize it as a Gradle project. You could do the rest of the required editing in the IDE.
Rename the generated src/components/HelloWorld.vue file to your {component-name}
:
FROM:
src/components/HelloWorld.vue
TO:
src/components/{component-name}.vue
In src/App.vue, rename the import for HelloWorld.vue and replace with your
{component-name}
file:
// FROM:
import HelloWorld from './components/HelloWorld.vue';
// TO:
import HelloWorld from './components/{component-name}.vue';
In App.vue you can change every instance of HelloWorld
to your {ComponentName}
:
<template>
<div id="app">
<img alt="Vue logo" src="./assets/logo.png" />
<HelloWorld msg="Welcome to Your Vue.js App" />
</div>
</template>
<script>
import HelloWorld from './components/{component-name}.vue';
export default {
name: 'app',
components: {
HelloWorld,
},
};
</script>
In src/components/{component-name}.vue you can change every instance
of HelloWorld
to your {ComponentName}
:
<script>
export default {
name: 'HelloWorld',
props: {
msg: String,
},
};
</script>
Note: in package.json the {component-name}
after --name
must
have a hyphen; for example --name weather-thingy
.
Change the following and replace {component-name}
with yours:
// FROM:
"build": "vue-cli-service build",
// TO (be sure to rename {component-name}):
"prebuild": "babel node_modules/@vue/web-component-wrapper/dist/vue-wc-wrapper.js -o node_modules/@vue/web-component-wrapper/dist/vue-wc-wrapper.js",
"build": "vue-cli-service build --name {component-name} --target wc src/components/{component-name}.vue",
Add these top-level declarations:
"main": "dist/{component-name}.js",
"source": "src/components/{component-name}.vue",
It should look something like this when you’ve finished editing:
{
"name": "weather-thingy",
"version": "0.1.0",
"private": true,
"main": "dist/weather-thingy.js",
"source": "src/components/weather-thingy.vue",
"scripts": {
"serve": "vue-cli-service serve",
"prebuild": "babel node_modules/@vue/web-component-wrapper/dist/vue-wc-wrapper.js -o node_modules/@vue/web-component-wrapper/dist/vue-wc-wrapper.js",
"build": "vue-cli-service build --name weather-thingy --target wc src/components/weather-thingy.vue",
"lint": "vue-cli-service lint"
},
...
}
Replace the contents of babel.config.js with this:
module.exports = {
presets: ['@babel/preset-env'],
plugins: [['@babel/plugin-transform-runtime', { useESModules: true }]],
};
To pack the component, run:
npm run build
You can optionally check that the component will run properly with:
npm run serve
Then go to the address specified in your browser (for example http://localhost:8080) to see if it displays.
To assemble the WebJar and put it in the local maven repo where the uPortal-start project can find it, run:
./gradlew install
The following is done in the uPortal-start project.
In the uPortal-start project make a copy of an existing portlet definition that has a web component.
COPY:
data/quickstart/portlet-definition/admin-dashboard.portlet-definition.xml
TO:
data/quickstart/portlet-definition/{component-name}.portlet-definition.xml
In the newly-created portlet-definition.xml, modify the following fields:
<title>Component Title</title>
<name>Component Name</name>
<fname>component-name</fname>
<desc>An excellent component that does something</desc>
Replace the CDATA section of the portlet definition with this, replacing
{component-name}
with your component name:
<portlet-preference>
<name>content</name>
<readOnly>false</readOnly>
<value>
<![CDATA[
<script src="/resource-server/webjars/vue/dist/vue.min.js"></script>
<script type="text/javascript" src="/resource-server/webjars/{component-name}/dist/{component-name}.min.js"></script>
<{component-name}></{component-name}>
]]>
</value>
</portlet-preference>
To find the name of the component min.js file that you will name in the script, examine the contents of the WebJar that was created. For example:
ls -al ~/.m2/repository/org/webjars/npm/weather-thingy/0.1.0-SNAPSHOT/*.jar
This shows the .jar file named:
weather-thingy-0.1.0-SNAPSHOT.jar
Now inspect the contents of the .jar file, for example:
jar tvf weather-thingy-0.1.0-SNAPSHOT.jar | grep min.js
This shows:
META-INF/resources/webjars/weather-thingy/0.1.0-SNAPSHOT/dist/weather-thingy.min.js
So the name of the min.js file is weather-thingy.min.js, which is what
you put in the CDATA <script>
tag.
To add Chrome (the standard border around portlets):
<parameter>
<name>chromeStyle</name>
<value>default</value>
</parameter>
To remove Chrome:
<parameter>
<name>chromeStyle</name>
<value>no-chrome</value>
</parameter>
To grant permission to everyone to browse for the web component and select it:
<group>Everyone</group>
<permissions>
<permission system="UP_PORTLET_SUBSCRIBE" activity="BROWSE">
<group>Everyone</group>
</permission>
</permissions>
In the overlays/resource-server/build.gradle file in the uPortal-start project, add the following runtime dependency:
runtime "org.webjars.npm:{component-name}:{version}@jar"
For example:
runtime "org.webjars.npm:weather-thingy:0.1.0-SNAPSHOT@jar"
Rebuild the uPortal-start project to populate the database with the new portlet definition and load the new WebJar into the resource server.
./gradlew portalInit
When you start uPortal, you should be able to find the new component when you select Customize > Add Stuff.
You can build and deploy a web component without having to restart the uPortal server and re-initialize uPortal data. Once the web component has been built and the WebJar dependency has been added to the resource server you can deploy it like this.
Re-build the resource-server so it pulls the new WebJar into its resources.
./gradlew :overlays:resource-server:build
Copy the newly-built resource-server.war file into the tomcat/webapps directory where it will automatically be deployed and overwrite the current one.
cp overlays/resource-server/build/libs/resource-server.war .gradle/tomcat/webapps/
It is better, and easier, to create the portlet definition .xml file and import it (Method 1) rather than add it in Portlet Administration in uPortal (Method 2), but you can do it both ways.
Import the portlet-definition.xml into the uPortal database.
./gradlew dataImport -Dfile=path/to/portlet-definition.xml
You will now be able to find your portlet in the Customize menu.
The problem with this method is that the definition is only temporary. It
is not included in the uPortal-start project and only resides in the
database. If you delete or refresh the database, for example with
./gradlew portalInit
, the portlet definition is gone.
In uPortal, navigate to Admin Tools > Portlet Administration.
In the Content Editor, select the Source button and paste the following and substite your component name:
<script src="/resource-server/webjars/vue/dist/vue.min.js"></script>
<script type="text/javascript" src="/resource-server/webjars/{component-name}/dist/{component-name}.min.js"></script>
<{component-name}></{component-name}>
You will now be able to find your portlet in the Customize menu.
Once you have built the web component and included it in uPortal, here is a way to speed up the rebuild and redeployment process so you can see your changes quickly in uPortal.
1. Re-build the web component.
npm run build
2. Re-package the WebJar and copy to local Maven repo for uPortal-start to use.
./gradlew install
You can do this while uPortal is still running which is why it’s much
faster. You don’t have to stop and restart uPortal which can take several
minutes. This assumes you used the uPortal-start project to run uPortal
locally with ./gradlew portalInit
and ./gradlew portalOpen
(or
./gradlew tomcatStart
) and that you have not stopped Tomcat (with
./gradlew tomcatStop
).
In the uPortal-start project root directory:
3. Re-build the resource-server so it pulls the new WebJar into its resources.
./gradlew :overlays:resource-server:build
4. Copy the newly-built resource-server.war file into the tomcat/webapps directory where it will automatically be deployed and overwrite the current one.
cp overlays/resource-server/build/libs/resource-server.war .gradle/tomcat/webapps/
5. Refresh the browser and you should see the changes.
To publish WebJars to a remote Maven repository, care must be taken when naming the artifacts. These instructions are for both the older maven plugin and the newer maven-publish plugin for Gradle.
In order to publish to a remote Maven repository correctly, you should use the Gradle group, project.name and project.version variables to name the artifact with the jar task of the Gradle java plugin. The maven and maven-publish plugins use these three variables to write the artifact to the Maven repository.
Here is a summary of the Gradle variables and how they are used:
If the group is org.webjars.npm, it will be published to:
org/webjars/npm/{project.name}/{project.version}/
The group is set in gradle.properties and should be org.webjars.npm to follow the standard convention for publishing WebJars:
group=org.webjars.npm
The project.name is read-only and is derived from the name of the project directory or from the rootProject.name variable. If you want the artifact name to be different than the project directory name, you can set rootProject.name in settings.gradle:
rootProject.name="some-other-name"
Setting rootProject.name is the proper way to name your artifact to something other than the project directory name if you want it to be published correctly to remote Maven repositories using the maven or maven-publish plugins.
You can see what these variables are by adding this to your build.gradle script:
println("group = ${group}")
println("project.name = ${project.name}")
println("project.version = ${project.version}")
println("rootProject.name = ${rootProject.name}")
NOTE: The maven and maven-publish plugins perform some additional magic on
versions named with -SNAPSHOT
when publishing to remote Maven repositories.
They add a timestamp to the name of the artifact and related files and store
the name of the most recent version in maven-metadata.xml in the same directory
so the most recent snapshot will be retrieved as a dependency in a project.
This works properly if you use the group, project.name and project.version
variables to name the artifact.
The Gradle maven plugin is the old way to publish. The maven-publish plugin is the new way.
Do not put the repository name and password in the project. You can store them
as variables in a gradle.properties file in the directory named in
the environment variable GRADLE_USER_HOME
. If GRADLE_USER_HOME
isn’t set,
Gradle defaults
to the $USER_HOME/.gradle
directory. See Gradle
Build Environment
for more.
For the build.gradle samples that follow, these variables are defined in
$USER_HOME/.gradle/gradle.properties
:
mavReleaseUser=relusername
mavReleasePass=secretRelUserPassword
mavSnapshotUser=snapusername
mavSnapshotPass=secretSnapUserPassword
Here is an example of a build.gradle file that uses the maven plugin to
publish. It includes both a snapshot repository and release repository.
It generates a snapshot version of the artifact. To build and publish a
release version, delete the + '-SNAPSHOT'
.
apply plugin: 'java'
apply plugin: 'maven'
def jsonFile = file("${projectDir}/package.json")
def parsedJson = new groovy.json.JsonSlurper().parseText(jsonFile.text)
project.version = parsedJson.version + '-SNAPSHOT'
/* remove '-SNAPSHOT' for release version */
jar {
archiveBaseName = project.name
from '.'
into "META-INF/resources/webjars/${project.name}/${project.version}"
include 'META-INF'
include 'dist/*'
exclude "dist/demo.html"
exclude "dist/${project.name}.js"
exclude "dist/${project.name}.js.map"
exclude "dist/${project.name}.min.js.map"
}
uploadArchives {
repositories {
mavenDeployer {
repository(url: "https://repo.school.edu/repo/release-repo") {
authentication(userName: "$mavReleaseUser", password: "$mavReleasePass")
}
snapshotRepository(url: "https://repo.school.edu/repo/snapshot-repo") {
authentication(userName: "$mavSnapshotUser", password: "$mavSnapshotPass")
}
}
}
}
To publish to a local Maven repository on your computer, run:
./gradlew install
The maven plugin recognizes the Maven install
command even though it’s not
listed as a task when you run ./gradlew tasks
.
To publish to a remote Maven repository, run:
./gradlew uploadArchives
The uploadArchives task of the maven plugin checks the release version
(0.1.0
versus 0.1.0-SNAPSHOT
) to decide to send it to the repository
location or the snapshotRepository
location.
The build.gradle file is simpler with the maven plugin, but is limited to only one release repository and one snapshot repository. The maven-publish plugin is more complicated but it can access more repositories.
Here is an example of a build.gradle file that uses the maven-publish plugin
to publish. It includes both a snapshot repository and release repository.
It generates a snapshot version of the artifact. To build and publish a
release version, delete the + '-SNAPSHOT'
.
apply plugin: 'java'
def jsonFile = file("${projectDir}/package.json")
def parsedJson = new groovy.json.JsonSlurper().parseText(jsonFile.text)
project.version = parsedJson.version + '-SNAPSHOT'
/* remove '-SNAPSHOT' for release version */
jar {
archiveBaseName = project.name
from '.'
into "META-INF/resources/webjars/${project.name}/${project.version}"
include 'META-INF'
include 'dist/*'
exclude "dist/demo.html"
exclude "dist/${project.name}.js"
exclude "dist/${project.name}.js.map"
exclude "dist/${project.name}.min.js.map"
}
apply plugin: 'java-library'
apply plugin: 'maven-publish'
publishing {
publications {
webJar(MavenPublication) {
artifact file("$buildDir/libs/${project.name}-${project.version}.jar")
}
}
repositories {
maven {
name = "myMaven"
def releaseRepoUrl = "https://repo.school.edu/repo/release-repo"
def releaseRepoUser = "$mavReleaseUser"
def releaseRepoPass = "$mavReleasePass"
def snapshotRepoUrl = "https://repo.school.edu/repo/snapshot-repo"
def snapshotRepoUser = "$mavSnapshotUser"
def snapshotRepoPass = "$mavSnapshotPass"
url = project.version.endsWith('SNAPSHOT') ? snapshotRepoUrl : releaseRepoUrl
credentials {
username = project.version.endsWith('SNAPSHOT') ? snapshotRepoUser : releaseRepoUser
password = project.version.endsWith('SNAPSHOT') ? snapshotRepoPass : releaseRepoPass
}
}
}
}
The maven-publish plugin does not recognize the Maven install
command.
To publish to a local Maven repository on your computer, run:
./gradlew publishToMavenLocal
To publish to a remote Maven repository, run:
./gradlew publishWebJarPublicationToMyMavenRepository
The maven-publish plugin doesn’t automatically decide to publish to a release
repository or a snapshot repository based on the release version (0.1.0
versus 0.1.0-SNAPSHOT
) like the maven plugin does, so this example mimics
that behavior with
ternary operators in the code.
The maven-publish plugin generates a new task, publishToMavenLocal,
and other tasks based on the name of the publication and the name of the
repository. Run ./gradlew tasks
and you will see the following Publishing
tasks that are automatically generated by the maven-publish plugin:
publishToMavenLocal
publishWebJarPublicationToMavenLocal
publishWebJarPublicationToMavenLocalRepository
publishWebJarPublicationToMyMavenRepository
The task name to publish to a remote repository,
publishWebJarPublicationToMyMavenRepository
, comes from the publication
name webJar()
and the repository name myMaven
. The task name convention
is:
publish{publication name}PublicationTo{repository name}Repository
The previous maven-publish example automatically detects which remote repository
to publish to based on -SNAPSHOT
in the version, but you could alternatively
define multiple repositories and explicitly publish to the one you want.
See this example:
apply plugin: 'java'
def jsonFile = file("${projectDir}/package.json")
def parsedJson = new groovy.json.JsonSlurper().parseText(jsonFile.text)
project.version = parsedJson.version + '-SNAPSHOT'
/* remove '-SNAPSHOT' for release version */
jar {
archiveBaseName = project.name
from '.'
into "META-INF/resources/webjars/${project.name}/${project.version}"
include 'META-INF'
include 'dist/*'
exclude "dist/demo.html"
exclude "dist/${project.name}.js"
exclude "dist/${project.name}.js.map"
exclude "dist/${project.name}.min.js.map"
}
apply plugin: 'java-library'
apply plugin: 'maven-publish'
publishing {
publications {
webJar(MavenPublication) {
artifact file("$buildDir/libs/${project.name}-${project.version}.jar")
}
}
repositories {
maven {
name = "myRelease"
url = "https://repo.school.edu/repo/release-repo"
credentials {
username = "$mavReleaseUser"
password = "$mavReleasePass"
}
}
maven {
name = "mySnapshot"
url = "https://repo.school.edu/repo/snapshot-repo"
credentials {
username = "$mavSnapshotUser"
password = "$mavSnapshotPass"
}
}
}
}
To publish to a local Maven repository on your computer, run:
./gradlew publishToMavenLocal
To publish to a remote Maven snapshot repository, run:
./gradlew publishWebJarPublicationToMySnapshotRepository
To publish to a remote Maven release repository, run:
./gradlew publishWebJarPublicationToMyReleaseRepository
Run ./gradlew tasks
and you will see the following Publishing tasks
that are automatically generated by the maven-publish plugin:
publishToMavenLocal
publishWebJarPublicationToMyReleaseRepository
publishWebJarPublicationToMySnapshotRepository
publishWebJarPublicationToMavenLocal
Windows has a quirk that the copyFiles and cleanUp tasks in this build.gradle file works around. This will also work on Mac OS and Linux.
apply plugin: 'java'
apply plugin: 'maven'
def jsonFile = file("${projectDir}/package.json")
def parsedJson = new groovy.json.JsonSlurper().parseText(jsonFile.text)
project.version = parsedJson.version + '-SNAPSHOT'
task copyFiles{
copy{
from ('.'){
exclude '*.lock'
exclude '**/*.lock'
exclude 'build/*'
exclude 'node_modules/*'
}
into 'build_tmp/target/content'
}
}
jar {
archiveBaseName = project.name
from '.'
into "META-INF/resources/webjars/${project.name}/${project.version}"
include 'META-INF'
include 'dist/*'
exclude "dist/demo.html"
exclude "dist/${project.name}.js"
exclude "dist/${project.name}.js.map"
exclude "dist/${project.name}.min.js.map"
}
task cleanUp(type: Delete) {
delete 'build_tmp'
followSymlinks = true
}
jar.finalizedBy cleanUp
sudo port list | grep node
sudo port install nodejs10
brew search node
brew install node