Compare commits

...

No commits in common. "master" and "router" have entirely different histories.

27 changed files with 12852 additions and 283 deletions

64
.gitignore vendored
View File

@ -1,63 +1 @@
*dist
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# OS Files
.DS_Store
node_modules

21
LICENSE
View File

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2018 RonnieSan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

100
README.md
View File

@ -1,99 +1,3 @@
# Vue SFC Compiler
# Vue Pages Router
> Template for build setup to compile Single File Components (.vue) into a standalone JS file for use in the browser
This template is useful for compiling VueJS single file components (SFC) into standalone JS files for use in the browser. This is useful for devs that want to create a simple component that can be used on a site without having to build an entire app around it, similar to the way a JQuery plugin might be used. The template, script, and styles are all compiled to a single JS file.
The compiler is setup to allow you to use either LESS or SASS (scss or sass) if you want to
As well as pug and **typescript** !
## Usage
This is a project template for [vue-cli](https://github.com/vuejs/vue-cli).
### 1. Create a new Vue project
At the command line, enter the following commands in parent folder of where you will be keeping your project.
``` bash
# Install vue-cli if you haven't already
$ npm install -g vue-cli
# Create a new project based on this template
$ vue init sheychen/vue-sfc-compiler my-project
# Navigate into your new project folder
$ cd my-project
# Install dependencies
$ npm install
```
### 2. Create and compile a component
Create a `.vue` file anywhere in the `src` folder of the project you just created.
Then, run the webpack compiler and point the `--env.file` argument to the .vue file you created (you don't need to add the extension). The path should be relative to the `src` folder, so if you created your `.vue` file in the `src` folder, the path would just be the name of the file. For example, if the file is located in `src/sub-folder/my-component.vue`, the path you would enter for the `--env.file` argument would be `sub-folder/my-component`.
``` bash
$ npm run build path/to/my-component.vue
```
``` bash
$ npm run watch path/to/my-component.vue
```
The webpack compiler runs in watch mode so any changes you make will update the compiled file. Whenever you make changes to you component, as long as the webpack compiler is running, the changes will be re-compiled and saved over the same output file. The compiled output file will be created at the same relative path in the `dist` folder that it was located in the `src` folder. So if you create a component at `src/some-sub-folder/my-rad-component.vue`, the compiled file will be located in `dist/some-sub-folder/my-rad-component.js`.
Once you've completed the development of your component and want to use it, you can take the compiled `.js` file and place it wherever you want.
Make sure you add a `name` property to the script section of the component. This is what will be used as the tag for your component when you use it in your app/HTML file.
Giving your component a name property of `my-component` means you will add your component to the app as `<my-component></my-component>`.
### 3. Use the compiled JS file
You will still need to include VueJS on your HTML page and create a root VueJS app in order to use your component.
Add a reference to the compiled component file (`.js`) in a script tag. Make sure it is added _AFTER_ you add VueJS to the page.
You can then include the component on your page using the `name` property you set as the tag.
``` html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>VueJS Component Test</title>
<script src="https://unpkg.com/vue"></script>
<script src="my-component.js"></script>
</head>
<body>
<div id="wrapper">
<my-component></my-component>
</div>
<script>
var app = new Vue({
el : '#wrapper'
});
</script>
</body>
</html>
```
## Included Example
The template package includes a sample component (`example.vue`) that you can test it all out with. The command you would use to compile it would be `webpack --env.file=example`. The component has a name property of `example`, the the tagname you would use in your HTML woudl be `<example></example>`.
The example component will print out the words "Hello, world." When the text is clicked, the word "world" will change to "foobar".
## Converting an existing Vue Single File Component to a standalone JS file
To convert an existing Vue Single File Component to a standalone JS file, simple add it to the `src` folder along with all the required dependencies (make sure all the paths are correct for the dependencies). Then run the compiler (`webpack` command) with the `--env.file` argument pointing to the component. If anything goes wrong, the compiler will tell you what errors occured.
## IMPORTANT!!!
* Make sure you give your component a `name` property. It will be used as the tagname for your component.
## Other Notes
* Excluding styles can greatly decrease the size of your compiled JS file as it doesn't need to add logic to inject the styles on the page
Unsafe component to load dynamic components using vue-sfc-compiler.

1
compiler/dist/core/pages-router.js vendored Normal file

File diff suppressed because one or more lines are too long

1
compiler/dist/test1.js vendored Normal file

File diff suppressed because one or more lines are too long

1
compiler/dist/test2.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -1,6 +1,6 @@
{
"name": "vue-browser-component",
"version": "1.0.0",
"version": "1.1.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@ -3686,12 +3686,14 @@
"balanced-match": {
"version": "1.0.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"brace-expansion": {
"version": "1.1.11",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"balanced-match": "^1.0.0",
"concat-map": "0.0.1"
@ -3706,17 +3708,20 @@
"code-point-at": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"concat-map": {
"version": "0.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"console-control-strings": {
"version": "1.1.0",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"core-util-is": {
"version": "1.0.2",
@ -3833,7 +3838,8 @@
"inherits": {
"version": "2.0.3",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"ini": {
"version": "1.3.5",
@ -3845,6 +3851,7 @@
"version": "1.0.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -3859,6 +3866,7 @@
"version": "3.0.4",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"brace-expansion": "^1.1.7"
}
@ -3866,12 +3874,14 @@
"minimist": {
"version": "0.0.8",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"minipass": {
"version": "2.3.5",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"safe-buffer": "^5.1.2",
"yallist": "^3.0.0"
@ -3890,6 +3900,7 @@
"version": "0.5.1",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"minimist": "0.0.8"
}
@ -3970,7 +3981,8 @@
"number-is-nan": {
"version": "1.0.1",
"bundled": true,
"dev": true
"dev": true,
"optional": true
},
"object-assign": {
"version": "4.1.1",
@ -3982,6 +3994,7 @@
"version": "1.4.0",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"wrappy": "1"
}
@ -4103,6 +4116,7 @@
"version": "1.0.2",
"bundled": true,
"dev": true,
"optional": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",

View File

@ -19,7 +19,9 @@
"component"
],
"author": "Shu",
"contributors": ["RonnieSan"],
"contributors": [
"RonnieSan"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/sheychen290/vue-sfc-compiler/issues"

View File

@ -0,0 +1,8 @@
<template lang="pug">
p(style="color: red") Can't load module
//TODO: Sad error
</template>
<script>
export default { }
</script>

View File

@ -0,0 +1,8 @@
<template lang="pug">
p Loading...
//TODO: Cool loader
</template>
<script>
export default { }
</script>

View File

@ -0,0 +1,139 @@
<template lang="pug">
.pages
.pages-list
slot(v-if="pages.error" name="error") {{ pages.error }}
slot(v-else-if="pages.data" name="list")
template(v-for="(page, id) in pages.data")
button(v-if="activePage != id" @click="showPage(id)") {{ page.name }}
p(v-else) {{ page.name }}
slot(v-else name="loader") Loading...
.active-page
div(v-if="activePage")
keep-alive
div(:is="activeComponent")
</template>
<script>
import PageLoader from './components/loader.vue'
import PageError from './components/error.vue'
export default {
name: 'pages-router',
data() {
return {
pages: {
error: null,
data: null
},
activePage: null
}
},
props: {
loader: {
type: Object,
default() {
return PageLoader
}
},
error: {
type: Object,
default() {
return PageError
}
},
prefix: {
type: String,
default: 'page-'
},
retry: {
type: Boolean,
default: false
},
source: {
required: true
},
timeout: {
type: Number,
default: 5000
},
title: {
type: String,
default: 'Router'
}
},
created() {
this.source.then(data => { // Load pages
this.pages.data = data
const loading = () => { // Show page from url or default one
this.showPage(window.location.hash.length > 0 ?
window.location.hash.substr(2) :
Object.keys(this.pages.data)[0])
}
this.$nextTick(loading)
window.onhashchange = loading
}).catch(error => {
this.pages.error = error
})
},
computed: {
activeComponent() {
return this.prefix + this.activePage
}
},
methods: {
showPage(id) {
const key = this.prefix + id
if (!(id in this.pages.data)) {
console.error(`Module not found: ${id}`)
this.$options.components[key] = this.error
return;
}
const mod = this.pages.data[id]
if (!(key in this.$options.components)) { // Must be load
this.$options.components[key] = () => ({
// Dynamicly load component
component: new Promise((resolve, reject) => {
const loaded = () => key in Vue.options.components
const load = () => loaded() ?
resolve(Vue.options.components[key]) : reject()
if (loaded() || (!this.retry && document.querySelector(`script[src="${mod.src}"]`))) { // Allready loaded
load()
return;
}
const remover = fn => e => {
if(this.retry) {
document.head.removeChild(e.target)
}
fn()
}
const el = document.createElement('script')
el.type = 'text/javascript'
el.async = true
el.src = mod.src
if (mod.integrity != null)
el.integrity = mod.integrity
el.addEventListener('load', remover(load))
el.addEventListener('error', remover(reject))
el.addEventListener('abort', remover(reject))
document.head.appendChild(el)
}),
loading: this.loader,
error: this.error,
timeout: this.timeout
})
}
document.title = `${this.title} - ${mod.name}`
window.history.pushState({}, document.title, "/#/" + id)
this.activePage = id
}
}
}
</script>

22
compiler/src/test1.vue Normal file
View File

@ -0,0 +1,22 @@
<template lang="pug">
p {{ yolol }}
</template>
<script>
export default {
name: 'page-test1', //Really important
data() {
return {
yolol: null
}
},
created() {
this.yolol = 'hello'
}
}
</script>
<style lang="sass" scoped>
p
font-style: italic
</style>

17
compiler/src/test2.vue Normal file
View File

@ -0,0 +1,17 @@
<template lang="pug">
p {{ yolo }}
</template>
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
@Component({ name: 'page-test2' }) //Really important
export default class Test2 extends Vue {
yolo = 'loading'
created() {
this.yolo = 'holla'
}
}
</script>

View File

@ -4,6 +4,6 @@
"strict": true,
"module": "es2015",
"moduleResolution": "node",
"experimentalDecorators": true
"experimentalDecorators": true,
}
}

View File

@ -6,10 +6,10 @@
// webpack --env.file="./path/to/file" --relative to the src folder
// Import dependencies
const path = require('path');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const path = require('path');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin');
const StringReplacePlugin = require('string-replace-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
function resolve(dir) {
return path.resolve(__dirname, dir);
@ -21,30 +21,29 @@ module.exports = (env) => {
const filepath = path.dirname(env.file);
return {
mode : 'production',
entry : {
[filename] : './entry.js'
mode: 'production',
entry: {
[filename]: './entry.js'
},
output : {
filename : '[name].js',
path : path.resolve(__dirname, 'dist', filepath)
output: {
filename: '[name].js',
path: path.resolve(__dirname, 'dist', filepath)
},
resolve : {
extensions : ['.ts', '.vue', '.js'],
alias : {
'vue$' : resolve('node_modules/vue/dist/vue.min.js'),
'@' : resolve('src')
resolve: {
extensions: ['.ts', '.vue', '.js'],
alias: {
'vue$': resolve('node_modules/vue/dist/vue.min.js'),
'@': resolve('src')
}
},
externals : {
vue : 'Vue',
lodash : 'lodash'
externals: {
vue: 'Vue'
},
module : {
rules : [
module: {
rules: [
{
test : /entry\.js$/,
loader : StringReplacePlugin.replace({
test: /entry\.js$/,
loader: StringReplacePlugin.replace({
replacements: [
{
pattern: /__FILE__/ig,
@ -52,11 +51,12 @@ module.exports = (env) => {
return env.file;
}
}
]})
]
})
},
{
test : /\.vue$/,
loader : 'vue-loader'
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.tsx?$/,
@ -67,9 +67,9 @@ module.exports = (env) => {
}
},
{
test : /\.js$/,
loader : 'babel-loader',
include : [
test: /\.js$/,
loader: 'babel-loader',
include: [
resolve('src')
],
exclude: file => (
@ -78,37 +78,37 @@ module.exports = (env) => {
)
},
{
test : /\.css$/,
use : [
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
},
{
test : /\.less$/,
use : [
test: /\.less$/,
use: [
'vue-style-loader',
'css-loader',
'less-loader'
]
},
{
test : /\.scss$/,
use : [
test: /\.scss$/,
use: [
'vue-style-loader',
'css-loader',
'sass-loader'
]
},
{
test : /\.sass$/,
use : [
test: /\.sass$/,
use: [
'vue-style-loader',
'css-loader',
{
loader : 'sass-loader',
options : {
indentedSyntax : true
loader: 'sass-loader',
options: {
indentedSyntax: true
}
}
]
@ -126,7 +126,7 @@ module.exports = (env) => {
performance: {
hints: false
},
plugins : [
plugins: [
new VueLoaderPlugin(),
new OptimizeCSSPlugin({
cssProcessorOptions: {

28
index.html Executable file
View File

@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Vue Pages Router</title>
<script src="lib/axios.js"></script>
<script src="lib/vue.full.js"></script>
<script src="compiler/dist/core/pages-router.js"></script>
</head>
<body>
<div id="app">
<noscript>Needs javascript enabled to work correctly. Sorry</noscript>
<pages-router :source="pages"></pages-router>
</div>
<script>
var app = new Vue({
el: '#app',
data: {
pages: axios.get('pages.json')
.then(res => res.data)
.catch(err => err.response.statusText)
}
})
</script>
</body>
</html>

1602
lib/axios.js Executable file

File diff suppressed because it is too large Load Diff

10947
lib/vue.full.js Executable file

File diff suppressed because it is too large Load Diff

View File

@ -1,3 +0,0 @@
{
"schema": {}
}

10
pages.json Normal file
View File

@ -0,0 +1,10 @@
{
"test1": {
"name": "Test1",
"src": "compiler/dist/test1.js"
},
"test2": {
"name": "Test2",
"src": "compiler/dist/test2.js"
}
}

View File

View File

@ -1,24 +0,0 @@
<template lang="pug">
div(@click="changeName()").
Hello, {{ name }}.
</template>
<script lang="ts">
import Vue from 'vue'
import Component from 'vue-class-component'
@Component({ name: 'example' })
export default class Example extends Vue {
name = 'world'
changeName() {
this.name = 'foobar'
console.log(this.name)
}
}
</script>
<style lang="sass" scoped>
div
font-weight: bold
</style>

View File

@ -1,25 +0,0 @@
<template lang="pug">
div(@click="changeName()").
Hello, {{ name }}.
</template>
<script>
export default {
name : 'example',
data() {
return {
name : 'world'
};
},
methods : {
changeName() {
this.name = 'foobar';
}
}
};
</script>
<style lang="sass" scoped>
div
font-weight: bold
</style>