Launch an App

This section introduces how to launch an app by packaging the minimal files needed for the UI inside the package.tgz.

 package.tgz
   ├── ui                       (specified by dsmuidir in INFO)
   |   ├── config               (the UI config file describing components in JavaScript file and their dependencies)
   |   ├── ExamplePackage.js    (the main JavaScript file of the package)
   |   └── style.css            (the style of the package)
   └── ....

To prepare the files (UI config, main JavaScript file) in package.tgz, organize your application source code in the ui folder in your package project. You can also use other names, but remember to match it with the dsmuidir specified in the INFO file during installation.

The project structure of the application ui might look like this:

ExamplePackage
└── ui
    ├── app.config
    ├── config.define
    ├── Makefile
    ├── package.json
    ├── pnpm-lock.yaml
    ├── src
    │   ├── App.vue
    │   │── components
    │   │   └── CustomForm.vue
    │   ├── main.js
    │   └── styles
    └── webpack.config.js

Here is the detailed information about the files mentioned above:

First, to generate the config file in package.tgz, prepare app.config, config.defind, and the Makefile

app.config

app.config describes the components in the package.

Format:

{
    "[Classname]": {
        "[Attribute]": "[Value]",
        ...
    }
}

Example:

{
    "SYNO.SDS.App.ExamplePackage.Instance": {
        "type": "app",
        "title": "ExamplePackage",
        "appWindow": "SYNO.SDS.App.ExamplePackage.Instance",
        "allUsers": true,
        "allowMultiInstance": false,
        "hidden": false,
        "icon": "images/icon.png"
    }
}

Attribute details:

Attribute Description Value
type specifies the type of this class String
title the title of package application String
appWindow specifies the classname of the AppWindow when opening this application String
allUsers set all users can use this app Boolean
allowMultiInstance application can be launched more then one instance Boolean
hidden set true to hide the package in the StartMenu Boolean
icon application icon String

config.define

config.define defines the deployed JavaScript file name which is installed in package.tgz. The JSfiles should include all the JavaScript files you want to deploy, typically the output of a bundling tool (e.g. webpack).

Example:

{
    "ExamplePackage.js":{
        "JSfiles": [
            "dist/example-package.bundle.js"
        ],
        "params": "-s -c skip"
    }
}

Makefile

This Makefile is used to manage the build process of package application.

include /env.mak
include ../Makefile.inc

JS_DIR="dist"                                 # the directory where your JavaScript files are stored
JS_NAMESPACE="SYNO.SDS.App.ExamplePackage"    # the class name prefix in your project, which should match the namespace defined in main.js
BUNDLE_JS="dist/example-package.bundle.js"
BUNDLE_CSS="dist/style/example-package.bundle.css"

.PHONY: all $(SUBDIR)

all: $(BUNDLE_JS) style.css $(SUBDIR)

$(BUNDLE_JS):
    # Snpm is a tool to install npm modules in Synology
    /usr/local/tool/snpm install
    /usr/local/tool/snpm run build
    $(MAKE) -f Makefile.js.inc JSCompress JS_NAMESPACE=\"${JS_NAMESPACE}\" JS_DIR=${JS_DIR}

$(SUBDIR):
    @echo "===>" $@
    $(MAKE) -C $@ INSTALLDIR=$(INSTALLDIR)/$@ DESTDIR=$(DESTDIR) PREFIX=$(PREFIX) $(MAKECMDGOALS);
    @echo "<===" $@

style.css: $(BUNDLE_JS)
    cp $(BUNDLE_CSS) $@

clean: clean_JSCompress $(SUBDIR)
    rm $(BUNDLE_JS)

install: $(SUBDIR) install_JSCompress
    [ -d $(INSTALLDIR)/dist/assets ] || install -d $(INSTALLDIR)/dist/assets
    install --mode 644 dist/assets/*.png $(INSTALLDIR)/dist/assets

include Makefile.js.inc

package.json

Also, you need a package.json for configure and describe the dependencies for your application.

{
    "name": "ExamplePackage",
    "private": true,
    "version": "1.0.0",
    "description": "",
    "main": "webpack.config.js",
    "scripts": {
        "build": "webpack --mode production",
        "dev": "webpack --watch --progress --mode development"
    },
    "keywords": [],
    "author": "",
    "license": "ISC",
    "devDependencies": {
        "@babel/core": "7.18.6",
        "babel-loader": "8.0.6",
        "terser-webpack-plugin": "5.3.10",
        "vue": "2.7.14",
        "vue-loader": "15.10.1",
        "vue-template-compiler": "2.7.14",
        "webpack": "5.91.0",
        "webpack-cli": "5.1.4"
    }
}

main.js

The file serves as the entry point for your bundle tool and initializes of your Vue application by setting up the necessary components and configurations.

import Vue from 'vue';
import App from './App.vue';

SYNO.namespace('SYNO.SDS.App.ExamplePackage');

// @require SYNO.SDS.App.ExamplePackage.ModalWindow
SYNO.SDS.App.ExamplePackage.Instance = Vue.extend({
    components: { App },
    template: '<App/>',
});

App.vue

Your app instance is defined here, allowing you to write Vue components to render your application, for more detail about UI framework please refer to DSM UI Framework.

<template>
    <v-app-instance class-name="SYNO.SDS.App.ExamplePackage.Instance">
        <v-app-window width=850 height=574 ref="appWindow" :resizable="false" syno-id="SYNO.SDS.App.ExamplePackage.Window">
            <div class="example-package-app">
                Hello Synology Package
            </div>
        </v-app-window>
    </v-app-instance>
</template>

<script>
export default {
    data() {
        return {
        };
    },
    methods: {
        close() {
            this.$refs.appWindow.close();
        },
    },
}
</script>
<style lang="scss">
.example-package-app {
    height: 100%;
}
</style>

webpack.config.js

const path = require('path');
const webpack = require('webpack');
const VueLoaderPlugin = require('vue-loader/lib/plugin');

module.exports = async (env, argv) => {
    const isDevelopment = argv.mode === 'development';
    return {
        mode: isDevelopment ? 'development' : 'production',
        devtool: isDevelopment ? 'inline-cheap-module-source-map' : false,
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    loader: 'vue-loader'
                },
                {
                    exclude: /node_modules/,
                    test: /\.js$/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            rootMode: 'upward'
                        }
                    }
                },
            ]
        },
        /* your package entry with Vue.extend and SYNO.namespace defined */
        entry: './src/main.js',
        output: {
            /* Need to write in config.define */
            filename: 'example-package.js',
            path: path.resolve('dist')
        },
        resolve: {
            extensions: ['.js', '.vue', '.json']
        },
        plugins: [
            new VueLoaderPlugin()
        ],
        externals: {
            'vue': 'Vue'
        },
        watchOptions: {
            poll: true
        }
    };
};

results matching ""

    No results matching ""