Git Product home page Git Product logo

sbt-vuefy's Introduction

sbt-vuefy

CircleCI codecov Gitter chat

sbt-vuefy integrates Vue's single components into Playframework. It hot-reloads the changes of Vue components while running Playframework with sbt run. It also works with sbt stage, which triggers the production build.

Both Typescript and Javascript components are supported and can be mixed. Please see the example project in the folder test-play-project.

This plugin is currently used at GIVE.asia, which has more than 200 Vue components in both Javascript and Typescript.

Requirements

  • Webpack 5.x and vue-loader 16.x: you'll need to specify the webpack binary location and webpack's configuration localtion. This enables you to choose your own version of Webpack and your own Webpack's configuration. You can see an example in the folder test-play-project.
  • Playframework 2.8.x
  • Scala >= 2.12.x and SBT 1.x: Because the artifact is only published this setting (See: https://search.maven.org/artifact/io.github.givesocialmovement/sbt-vuefy/6.0.0/jar). If you would like other combinations of Scala and SBT versions, please open an issue.

How to use

1. Install the plugin

Add the below line to project/plugins.sbt:

For Playframework 2.8.x and Vue 3:

addSbtPlugin("io.github.givesocialmovement" % "sbt-vuefy" % "6.0.0")

The artifacts are published to Maven Central here: https://search.maven.org/artifact/io.github.givesocialmovement/sbt-vuefy/6.0.0/jar

2. Configure Webpack config file.

Create webpack.config.js with vue-loader. Below is a working minimal example:

"use strict";

const {VueLoaderPlugin} = require('vue-loader');

module.exports = {
  plugins: [new VueLoaderPlugin()],
  stats: 'minimal',
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader',
      },
      {
        test: /\.scss$/,
        exclude: /node_modules/,
        use: [
          'style-loader',
          'css-loader',
          'sass-loader'
        ],
      },
      {
        test: /\.ts$/,
        loader: 'ts-loader',
        options: {
          appendTsSuffixTo: [/\.vue$/],
        }
      }
    ]
  },
  resolve: {
    extensions: ['.ts', '.js', '.vue']
  }
};

You should NOT specify module.exports.output because sbt-vuefy will automatically set the field.

Your config file will be copied and added with some required additional code. Then, it will used by sbt-vuefy when compiling Vue components.

When running sbt-vuefy, we print the webpack command with the modified webpack.config.js, so you can inspect the config that we use.

To make it work with Typescript, tsconfig.json is also needed to be setup. Please see test-play-project for a working example.

3. Configure build.sbt

Specifying necessary configurations:

lazy val root = (project in file(".")).enablePlugins(PlayScala, SbtWeb, SbtVuefy) // Enable the plugin

// The commands that triggers production build when running Webpack, as in `webpack --mode production`.
Assets / VueKeys.vuefy / VueKeys.prodCommands := Set("stage")

// The location of the webpack binary. For windows, it might be `webpack.cmd`.
Assets / VueKeys.vuefy / VueKeys.webpackBinary := "./node_modules/.bin/webpack"

// The location of the webpack configuration.
Assets / VueKeys.vuefy / VueKeys.webpackConfig := "./webpack.config.js"

4. Find out where the output JS file is and how to use it

The plugin compiles *.vue within app/assets.

For the path app/assets/vue/components/some-component.vue, the output JS should be at http://.../assets/vue/components/some-component.js. It should also work with @routes.Assets.versioned("vue/components/some-component.js").

The exported module name is the camel case of the file name. In the above example, the module name is SomeComponent.

Therefore, we can use the component as shown below:

<script src="https://unpkg.com/vue@@3.0.4/dist/vue.runtime.global.js"></script>
<script src='@routes.Assets.versioned("vue/components/some-component.js")'></script>

<div id="app"></div>
<script>
  Vue
      .createApp({
        render: function() {
          return Vue.h(SomeComponent.default, {
            someProp: "SomePropValue"
          });
        }
      })
      .mount('#app');
</script>

Please see the folder test-play-project for a complete example.

Interested in using the plugin?

Please feel free to open an issue to ask questions. Let us know how you want to use the plugin. We want to help you use the plugin successfully.

Contributing

The project welcomes any contribution. Here are the steps for testing when developing locally:

  1. Run yarn install in order to install packages needed for the integration tests.
  2. Run sbt test to run all tests.
  3. To test the plugin on an actual Playframework project, go to test-play-project, run yarn install, and run sbt run.

Publish

  1. Get the latest master by running git fetch.
  2. Run sbt clean publish to publish.
  3. Tag the current commit with the current version: git tag -a v[VERSION] -m "Version v[VERSION]" and git push origin --tags.

Future improvement

  • Currently, the plugin doesn't track CSS dependencies (e.g. using @import) because webpack/vue-loader doesn't track these dependencies. We need to find a way. See the ongoing issue: #20
  • VueKeys.prodCommands is hacky. I use this approach because I don't have good understanding in SBT's scoping. There must be a better way of implementing the production build setting.

sbt-vuefy's People

Contributors

lukaszbyczynski avatar tanin47 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar

sbt-vuefy's Issues

Cannot compile project

Looks like an interesting project but I cannot compile the test project. The error reads -

error: not found: value SbtVuefy

This has brought up other errors on the build as doesn't recognise Assets or VueKeys. So it seems that the SBT files aren't available for some reason. The build/spec is the same of course, i.e. Scala 2.12.8 / SBT 1.2.8 / Play 2.7.3. I've read this similar issue - but it didn't help. To note: I used npm install instead of yarn install as I wasn't able to install yarn with the error -

'yarn' is not recognized as an internal or external command, operable program or batch file.

Hopefully that's not an issue. Any help/guidance is greatly appreciated!
_

How to use component with Play's Redirect statement

Any suggestion about how vue works with Play's Redirect statement:

like in the controller will return

Redirect(routes.Controller.viewSomething()).flashing("success" -> "success.")

then vue will get a response with the rendered html data. Is it possible to use this data rerender the page in vue?

Multiple entrypoints

Hi,

I'm using your seed for my company, this was very helpful, thanks.

To optimize my front-end application, I want to have multiple JS entrypoints (Vue3)
I managed to produce my multiple entrypoints files, to call each specific script per page (in scala template), like :
One file for my shop page

const app = createApp({});
app.component('v-header', Header)
app.component('v-shop', Shop)
export default app.mount('#app');

One file for my cart page

const app = createApp({});
app.component('v-header', Header)
app.component('v-cart', Cart)
export default app.mount('#app');

But I dont manage to have a library like vue-toaster in my Header component

Because my header is like : export default defineComponent({})
And I dont have the app instance to call app.use(Toaster) like I should.

Did you get something like that working ?
Regards

How to use it without render function?

The provided example works fine when using a render function in index.scala.html. However, I'd rather want to not use a render function as simple "loader", but instead use custom tags like <greeting-form> in the Twirl template. E.g.

@(greeting: String)

<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.16/vue.js"></script>
<script src='@routes.Assets.versioned("vue/components/greeting-form.js")'></script>

<div id="app">
    <p>Container</p>
    <greeting-form v-bind:greeting="'@greeting'">
</div>

<script>
    import('@routes.Assets.versioned("vue/components/greeting-form.js")').default
    Vue.component('greeting-form', GreetingForm);
    
    var app = new Vue({
        el: '#app'
    })
</script>

How can we achieve this behaviour?

Thanks!

vue-resource in multiple components : should I have a main.js file ?

Hi,

I try to import and use vue-resource in multiple components.
First, I tried to import in each single file component, but got the error Cannot redefine property: $url

Second, I tried to import vue-resource in the index.scala.html, when instancianting Vue :

<script>
    import Vue from 'Vue'
    import Resource from 'vue-resource';
    Vue.use(Resource);

    Vue.config.productionTip = false

    Vue.component('v-header', Header.default);
    Vue.component('product-page-cart', Product.default);

    new Vue({
      el: '#app',
      data: ... 
</script>

But I get the TypeScript compilation error on my component files : Property '$http' does not exist

I now try to have a main.js file, but still gets the $http does not exists error.

How do you get vue-resource working in a realworld project ?

Regards

Unresolved dependencies givers.vuefy#sbt-vuefy;3.0.0: not found

I am not able to add plugin as I get:

Error:Unresolved dependencies: givers.vuefy#sbt-vuefy;3.0.0: not found

This is how my plugins.sbt looks like:

// The Play plugin
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.6.2")

// Web plugins
addSbtPlugin("com.typesafe.sbt" % "sbt-coffeescript" % "1.0.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-less" % "1.0.6")
addSbtPlugin("com.typesafe.sbt" % "sbt-jshint" % "1.0.3")
addSbtPlugin("com.typesafe.sbt" % "sbt-rjs" % "1.0.7")
addSbtPlugin("com.typesafe.sbt" % "sbt-digest" % "1.1.0")
addSbtPlugin("com.typesafe.sbt" % "sbt-mocha" % "1.1.0")

// Play enhancer - this automatically generates getters/setters for public fields
// and rewrites accessors of these fields to use the getters/setters. Remove this
// plugin if you prefer not to have this feature, or disable on a per project
// basis using disablePlugins(PlayEnhancer) in your build.sbt
addSbtPlugin("com.typesafe.sbt" % "sbt-play-enhancer" % "1.1.0")

resolvers += Resolver.bintrayRepo("givers", "maven")
addSbtPlugin("givers.vuefy" % "sbt-vuefy" % "3.0.0")

Vue dependency missing?

I've run into an error when starting the app:

ERROR in ./vue/components/common/our-button.vue
Module build failed: Error:
Vue packages version mismatch:

It was using my old version and npm install vue helped, but I suggest to add vue itself also as dependency to ensure this works out of the box.

Cool project - exactly what we consider using in our next project. Thanks!

Error in Build.sbt

My project isn't compiling due to an error in the build.sbt -- it's giving an error value / is not a member of sbt.Configuration

It also points to the / in the line Assets / Vuekeys.vuefy ... and says that there's an type error in expression -- how should i resolve this?

Bintray Repository deprecated

Since 1st of May, the bintray repository has been deprecated. Could we move the packages to some other repository?

Add `"use strict";` to `sbt-vuefy-plugin.js`.

Would you be able to add "use strict"; to sbt-vuefy-plugin.js? Keep getting SyntaxError: Block-scoped declarations (let, const, function, class) not yet supported outside strict mode when I run sbt.

sbt stage does not create a runnable production build

The instruction indicate that to create production deployment, you should use sbt stage. However, in the basic test app this does not yield a runnable build:

$ sbt stage
[info] Loading settings for project plugins from plugin.sbt ...
[info] Loading settings for project sbt-vuefy-build from plugins.sbt ...
[info] Loading project definition from /Users/nford/echelon/sbt-vuefy/project
[info] Loading settings for project sbt-vuefy from version.sbt,build.sbt ...
[info] Loading project definition from /Users/nford/echelon/sbt-vuefy/test-play-project/project
[info] Loading settings for project root from build.sbt ...
[info] Set current project to test-play-project (in build file:/Users/nford/echelon/sbt-vuefy/test-play-project/)
[info] Packaging /Users/nford/echelon/sbt-vuefy/test-play-project/target/scala-2.12/test-play-project_2.12-1.0-SNAPSHOT-sources.jar ...
[info] Done packaging.
[info] Wrote /Users/nford/echelon/sbt-vuefy/test-play-project/target/scala-2.12/test-play-project_2.12-1.0-SNAPSHOT.pom
[info] Main Scala API documentation to /Users/nford/echelon/sbt-vuefy/test-play-project/target/scala-2.12/api...
[info] [Vuefy] Compile on 1 changed files
[info] /Users/nford/echelon/sbt-vuefy/test-play-project/node_modules/webpack/bin/webpack.js --config /var/folders/83/9023vzns5vjd_fnfmtskwddw0000gp/T/sbt-vuefy3744603403231261495/webpack.config.js --output-path /Users/nford/echelon/sbt-vuefy/test-play-project/target/web/vuefy/main -p
Webpack for development
model contains 17 documentable templates
[info] Main Scala API documentation successful.
[info] Packaging /Users/nford/echelon/sbt-vuefy/test-play-project/target/scala-2.12/test-play-project_2.12-1.0-SNAPSHOT-javadoc.jar ...
[info] Done packaging.
   10 modules
[info] Webpack exited with 0
[info] [Vuefy] finished compilation in 11361 ms and generated 1 JS files
[info] Packaging /Users/nford/echelon/sbt-vuefy/test-play-project/target/scala-2.12/test-play-project_2.12-1.0-SNAPSHOT-web-assets.jar ...
[info] Done packaging.
[info] Packaging /Users/nford/echelon/sbt-vuefy/test-play-project/target/scala-2.12/test-play-project_2.12-1.0-SNAPSHOT.jar ...
[info] Done packaging.
[info] Packaging /Users/nford/echelon/sbt-vuefy/test-play-project/target/scala-2.12/test-play-project_2.12-1.0-SNAPSHOT-sans-externalized.jar ...
[info] Done packaging.
$ ll target/universal/scripts/bin/
total 28
drwxr-xr-x 4 nford staff   128 Feb 14 14:51 .
drwxr-xr-x 3 nford staff    96 Feb 14 14:51 ..
-rwxr--r-- 1 nford staff 12575 Feb 14 14:51 test-play-project
-rw-r--r-- 1 nford staff  8441 Feb 14 14:51 test-play-project.bat
$ target/universal/scripts/bin/test-play-project -Dplay.http.secret.key='Q]WIB@IDFbM8odLosr[PyZJNT:r:tpP^I6iFV[ObJgcF@DQ3X`Hzu/aS?v?/aD:Q'
Error: Could not find or load main class play.core.server.ProdServerStart
Caused by: java.lang.ClassNotFoundException: play.core.server.ProdServerStart

(The key used here is just one I generated locally to test this plugin.)

Looking at the Play Framework deployment documentation it seems like they recommend using dist for a production artifact and stage for testing production 'in place'. However, while using dist (as in sbt dist) creates a deployable artifact it doesn't seem to include any of the compiled javascript. Similarly, using target/universal/stage/bin/test-play-project results in a runnable application but no compiled Vue assets. (The server says the javascript doesn't exist.)

I'm by no means an sbt expert but I'm not clear what needs to be done to close the gap. In the documentation you indicate using the -p flag, but I don't know what that refers to (sbt stage -p just fails). Any thoughts on what might be going on here?

Component .js files not generating correctly on Windows due to backslashes

There may be an issue generating component .js files when building on Windows. I have a component named LinkViews.vue that generates a corresponding link-views.js. On Windows, I get this error in Chrome: "Uncaught SyntaxError: Invalid or unexpected token" relating to line 1 in link-views.js, which looks like this:

var Vue\components\linkViews =

Comparatively, on MacOS or Linux there is no error. The line looks like this:

var LinkViews =

Seems related to the fact Windows uses backslashes instead of slashes. Let me know if you don't have access to a Windows machine and need me to test a possible fix.

Thanks, Nir

Components lose reactivity with sbt-vuefy

Thanks so much for making this! I'm very excited about the possibility of using sbt-vuefy to create single-page components instead of having them in template files. It took me a while to figure out how to set it up. The library dependency for sbt-vuefy doesn't seem to resolve on Play 2.5 so I had to upgrade to Play 2.6, and since I'm completely unfamiliar with npm and webpack, I didn't realize I was supposed to copy package.json from the test project to my own project and run npm install.

I only have one (recursive) Vue component right now for displaying threaded comments, and it works great in the template, but when I move it to a .vue file, even though it compiles just fine and the comment tree displays initially, a lot of the reactivity is gone. In link-comment.vue, I define these props:

        props: {
            comment: { type: Object, required: true },
            commentArray: { type: Array, required: true },
        }

And instantiate thusly:

        <link-comment v-for="childComment in comment.replies"
                      :key="childComment.commentId"
                      :comment="childComment"
                      :comment-array="comment.replies"></link-comment>

All of the reactive data is really in the comment prop, which is an object that has various attributes, example json:

{
   commentId: 368,
   userName: "Kirk Avocado",
   commentText: "The universe was a mistake.",
   likeCount: 1,
   liked: false,
   ownComment: true,
   replies: [...]
}

These two methods for example, change comment.liked, comment.likeCount, and the comment.replies array, and I can verify in the browser debugger that the object data changes and stays changed, but none of the changes are rendered:

toggleLike: function() {
                let comment = this.comment;

                $.ajax({
                    method: 'POST',
                    url: comment.liked ? '/api/unlike_link_comment' : '/api/like_link_comment',
                    contentType: "application/json; charset=utf-8",
                    data: JSON.stringify({ commentId: comment.commentId }),
                    dataType: 'json',
                    success: function (response) {
                        if (comment.liked) {
                            comment.liked = false;
                            comment.likeCount--;
                        } else {
                            comment.liked = true;
                            comment.likeCount++;
                        }
                    },
                    error: function (req, status, error) {
                    }
                });
            },
            deleteComment: function() {
                let data = this;

                if (confirm('Delete your comment?')) {
                    $.ajax({
                        method: 'POST',
                        url: '/api/delete_link_comment',
                        contentType: "application/json; charset=utf-8",
                        data: JSON.stringify({
                            commentId: data.comment.commentId
                        }),
                        dataType: 'json',
                        success: function () {
                            data.commentArray.splice(data.commentArray.indexOf(data.comment), 1);
                        },
                        error: function (req, status, error) {
                        }
                    });
                }
            }

Weirdly other changes like editing a comment (which changes comment.commentText) or adding a reply (which modifies the comment.replies array) do render. There's no rhyme or reason to it.

I realize this seems more like a VueJS problem, but it all works when the components are in the template, so I'm wondering is something is lost along the way when the .vue file is compiled that breaks reactivity...

I'm happy to send you the entire .vue file and complete JSON data to initialize it with if you deem it necessary.

Thanks, Nir

Upgrade to webpack 4

Webpack 4 has been released for a few months now. Let's move to the version 4.

Bintray repo not available anymore

Thank you for the sbt-vuefy plugin!
Our project-build recently started failing, because the Bintray repo isn't available anymore.
Is there a plan to move to another repo soon?

We're using version 5.0.0

Many thanks

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.