Skip to content

Added support for VueJS Single File Components w/ example #11

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Feb 8, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 17 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,23 @@ module.exports = {
}
```

### VueJS support

`py-loader` can also be used to compile .vue Single File Components used by (VueJS)[https://www.vuejs.org]. This assumes that you already have `vue-loader` set up and working with javascript .vue files. Modify your `vue-loader` config file as shown:

```js
loaders: {
'py': require.resolve('py-loader')
},
```

An example of a simple VueJS app written in (mostly) Python can be seen in the `examples/vue-demo` folder.

***Caveats***
* Only tested with Transcrypt
* The import statement for loading sub-components still looks a bit weird
* Web-pack entry point is still a javascript file

## Extend

`py-loader` can be extended to use other Python compilers. Just fork this repo and extend the `compilers` object in `index.js`.
Expand All @@ -58,4 +75,3 @@ Please submit a pull request with your addition.
- DuncanMacWeb (https://github.com/DuncanMacWeb)
- Sebastian Silva (https://github.com/icarito)
- Ryan Liao (https://github.com/pirsquare)

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
6 changes: 6 additions & 0 deletions examples/vue-demo/.babelrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"presets": [
["env", { "modules": false }],
"stage-3"
]
}
9 changes: 9 additions & 0 deletions examples/vue-demo/.editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
root = true

[*]
charset = utf-8
indent_style = space
indent_size = 2
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
15 changes: 15 additions & 0 deletions examples/vue-demo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.DS_Store
node_modules/
dist/
npm-debug.log
yarn-error.log
__javascript__/

# Editor directories and files
.idea
*.suo
*.ntvs*
*.njsproj
*.sln

yarn.lock
18 changes: 18 additions & 0 deletions examples/vue-demo/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# vue-demo

> A Vue component demo made in Python

## Build Setup

``` bash
# install dependencies
npm install

# serve with hot reload at localhost:8080
npm run dev

# build for production with minification
npm run build
```

For detailed explanation on how things work, consult the [docs for vue-loader](http://vuejs.github.io/vue-loader).
11 changes: 11 additions & 0 deletions examples/vue-demo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>vue-demo</title>
</head>
<body>
<div id="app"></div>
<script src="/dist/build.js"></script>
</body>
</html>
34 changes: 34 additions & 0 deletions examples/vue-demo/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "vue-demo",
"description": "A Vue component demo made in Python",
"version": "1.0.0",
"author": "Thomas Antony <tantony@purdue.edu>",
"license": "MIT",
"private": true,
"scripts": {
"dev": "cross-env NODE_ENV=development webpack-dev-server --open --hot",
"build": "cross-env NODE_ENV=production webpack --progress --hide-modules"
},
"dependencies": {
"vue": "^2.5.11"
},
"browserslist": [
"> 1%",
"last 2 versions",
"not ie <= 8"
],
"devDependencies": {
"babel-core": "^6.26.0",
"babel-loader": "^7.1.2",
"babel-preset-env": "^1.6.0",
"babel-preset-stage-3": "^6.24.1",
"cross-env": "^5.0.5",
"css-loader": "^0.28.7",
"file-loader": "^1.1.4",
"py-loader": "file:../..",
"vue-loader": "^13.0.5",
"vue-template-compiler": "^2.4.4",
"webpack": "^3.6.0",
"webpack-dev-server": "^2.9.1"
}
}
28 changes: 28 additions & 0 deletions examples/vue-demo/src/App.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<template>
<div id="app">
<img src="./assets/logo.png">
<hello-world />
</div>
</template>

<script lang="py">
# Loading sub-components (still a little ugly)
HelloWorld = require('./HelloWorld.vue')['default']

module.exports = {
'name': 'app',
'components': {
'hello-world': HelloWorld
}}
</script>

<style>
#app {
font-family: 'Avenir', Helvetica, Arial, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-align: center;
color: #2c3e50;
margin-top: 60px;
}
</style>
24 changes: 24 additions & 0 deletions examples/vue-demo/src/HelloWorld.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<template>
<div class="hello">
<h1>{{ msg }}</h1>
</div>
</template>

<script lang="py">
class HelloWorld(object):
name = 'HelloWorld'
def data(self):
return {'msg': 'Hello from Python!'}

module.exports = HelloWorld()
</script>

<!-- Add "scoped" attribute to limit CSS to this component only -->
<style scoped>
h1, h2 {
font-weight: normal;
}
a {
color: #42b983;
}
</style>
Binary file added examples/vue-demo/src/assets/logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
8 changes: 8 additions & 0 deletions examples/vue-demo/src/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// This is still JS webpack apparently doesn't like non-JS entry points
import Vue from 'vue'
import App from './App.vue'

new Vue({
el: '#app',
render: h => h(App)
})
80 changes: 80 additions & 0 deletions examples/vue-demo/webpack.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
var path = require('path')
var webpack = require('webpack')

module.exports = {
entry: './src/main.js',
output: {
path: path.resolve(__dirname, './dist'),
publicPath: '/dist/',
filename: 'build.js'
},
module: {
rules: [
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
],
},
{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
'py': require.resolve('py-loader')
}
// other vue-loader options go here
}
},
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/
},
{
test: /\.(png|jpg|gif|svg)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
}
]
},
resolve: {
alias: {
'vue$': 'vue/dist/vue.esm.js'
},
extensions: ['*', '.js', '.vue', '.json']
},
devServer: {
historyApiFallback: true,
noInfo: true,
overlay: true
},
performance: {
hints: false
},
devtool: '#eval-source-map'
}

if (process.env.NODE_ENV === 'production') {
module.exports.devtool = '#source-map'
// http://vue-loader.vuejs.org/en/workflow/production.html
module.exports.plugins = (module.exports.plugins || []).concat([
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
}),
new webpack.optimize.UglifyJsPlugin({
sourceMap: true,
compress: {
warnings: false
}
}),
new webpack.LoaderOptionsPlugin({
minimize: true
})
])
}
31 changes: 21 additions & 10 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,12 @@ module.exports = function (source) {
const entry = this._module.resource;
//console.log(`py-loader: compiling ${entry} with ${compilerName}...`);

const basename = path.basename(entry, ".py");
const srcDir = path.dirname(entry, ".py");
const fileinfo = path.parse(entry);

const srcDir = fileinfo.dir; // path.dirname(entry, ".py");
var basename = fileinfo.name;
var delete_after = false;
// const basename = path.basename(entry, ".py");
const callback = this.async();

if (compiler.streaming) {
Expand Down Expand Up @@ -88,17 +91,24 @@ module.exports = function (source) {
child.stdin.end();
}
else {
cmd.get(`${compiler.name} ${compiler.switches} ${srcDir}${slash}${basename}.py`, function(err, data, stderr) {

if (!entry.toLowerCase().endsWith(".py")) {
console.warn("This loader only handles .py files. This could be a problem with your webpack.config.js file. Please add a rule for .py files in your modules entry.");
callback(null, source);
}

if (fileinfo.ext == ".vue") {
basename = `__${fileinfo.name}`
delete_after = true;
fs.writeFileSync(`${srcDir}${slash}__${fileinfo.name}.py`, source);
}else if(fileinfo.ext != ".py")
{
console.warn("This loader only handles .py files. This could be a problem with your webpack.config.js file. Please add a rule for .py files in your modules entry.");
callback(null, source);
return;
}
cmd.get(`${compiler.name} ${compiler.switches} '${srcDir}${slash}${basename}.py'`, function(err, data, stderr) {
if (!err) {
const filename = `${srcDir}${slash}${compiler.folder}${slash}${basename}.js`;
js = fs.readFileSync(filename, "utf8");
fs.unlinkSync(filename);
if(delete_after){
fs.unlinkSync(`${srcDir}${slash}__${fileinfo.name}.py`);
}

if (compiler.sourcemaps) {
const sourceMapFile = `${srcDir}${slash}${compiler.folder}${slash}extra${slash}sourcemap${slash}${basename}.js`;
Expand All @@ -111,7 +121,8 @@ module.exports = function (source) {

}
else {
console.error(`Some error occurred on ${properName(compiler.name)} compiler execution. Have you installed ${properName(compiler.name)}? If not, please run \`${compiler.install}\` (requires Python ${compiler.python_version})`);
console.log(stderr)
// console.error(`Some error occurred on ${properName(compiler.name)} compiler execution. Have you installed ${properName(compiler.name)}? If not, please run \`${compiler.install}\` (requires Python ${compiler.python_version})`);
callback(err);
}

Expand Down