├── .gitattributes
├── .remarkignore
├── template
├── template.js
├── tailwind.css
└── index.template.html
├── bin
└── cli.js
├── .gitignore
├── tailwind.config.js
├── test
├── fixtures
│ ├── components
│ │ └── BaseButton.vue
│ ├── Header.vue
│ └── App.vue
└── test.js
├── .travis.yml
├── .editorconfig
├── src
├── index.js
├── plugins.js
├── cli.js
├── utils.js
├── compile-to-html.js
└── compile-to-component.js
├── .lintstagedrc.js
├── rollup.config.js
├── LICENSE
├── package.json
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | * text=auto
2 |
--------------------------------------------------------------------------------
/.remarkignore:
--------------------------------------------------------------------------------
1 | test/snapshots/**/*.md
2 |
--------------------------------------------------------------------------------
/template/template.js:
--------------------------------------------------------------------------------
1 | // This need to be empty!!
2 |
--------------------------------------------------------------------------------
/bin/cli.js:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env node
2 | require('../dist/cli');
3 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.log
3 | .idea
4 | node_modules
5 | coverage
6 | .nyc_output
7 | dist
--------------------------------------------------------------------------------
/tailwind.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | theme: {},
3 | variants: {},
4 | plugins: []
5 | };
6 |
--------------------------------------------------------------------------------
/test/fixtures/components/BaseButton.vue:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
--------------------------------------------------------------------------------
/template/tailwind.css:
--------------------------------------------------------------------------------
1 | @import "tailwindcss/base";
2 | @import "tailwindcss/components";
3 | @import "tailwindcss/utilities";
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '12'
4 | - 'lts/*'
5 | - 'node'
6 | script:
7 | npm run test-coverage
8 | after_success:
9 | npm run coverage
10 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | root = true
2 |
3 | [*]
4 | indent_style = space
5 | indent_size = 4
6 | end_of_line = lf
7 | charset = utf-8
8 | trim_trailing_whitespace = true
9 | insert_final_newline = true
10 |
--------------------------------------------------------------------------------
/src/index.js:
--------------------------------------------------------------------------------
1 | import compileToHTML from './compile-to-html';
2 | import compileToComponent from './compile-to-component';
3 |
4 | export default {
5 | compileToHTML,
6 | compileToComponent
7 | };
8 |
--------------------------------------------------------------------------------
/.lintstagedrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | "*.md,!test/**/*.md": [
3 | filenames => filenames.map(filename => `remark ${filename} -qfo`)
4 | ],
5 | 'package.json': 'fixpack',
6 | '*.js': 'xo --fix'
7 | };
8 |
--------------------------------------------------------------------------------
/template/index.template.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {{ title }}
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/test/fixtures/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 | This is header, {{ name }}
4 |
5 |
6 |
7 |
14 |
15 |
20 |
--------------------------------------------------------------------------------
/test/fixtures/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Hello {{ name }}
5 |
6 |
7 |
8 |
18 |
19 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import resolve from '@rollup/plugin-node-resolve';
2 | import { brotliCompressSync } from 'zlib';
3 | import { terser } from "rollup-plugin-terser";
4 | import gzipPlugin from 'rollup-plugin-gzip';
5 |
6 | export default {
7 | input: ['src/index.js', 'src/cli.js'],
8 | output: {
9 | dir: 'dist',
10 | format: 'cjs'
11 | },
12 | plugins: [
13 | resolve(),
14 | terser(),
15 | gzipPlugin({
16 | customCompression: content =>
17 | brotliCompressSync(Buffer.from(content)), fileName: '.br'
18 | })
19 | ]
20 | };
21 |
--------------------------------------------------------------------------------
/test/test.js:
--------------------------------------------------------------------------------
1 | const test = require('ava');
2 | const fs = require('fs-extra');
3 |
4 | const { compileToHTML } = require('../dist');
5 |
6 | test.beforeEach(t => {
7 | Object.assign(t.context, { props: 'Athif Humam' });
8 | });
9 |
10 | // Remove html_components folder after each test
11 | test.afterEach(async _ => {
12 | await fs.rmdir('html_components', async err => {
13 | if (err) {
14 | throw err;
15 | }
16 | });
17 | });
18 |
19 | test('can render html', async t => {
20 | const { App } = await compileToHTML('./fixtures/App.vue', {
21 | props: { name: t.context.props }
22 | });
23 | const result =
24 | '\n' +
25 | ' This is header, Athif Humam\n';
26 |
27 | t.true(App.includes(result));
28 | });
29 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Muhammad Athif Humam (https://athif23.github.io/)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/plugins.js:
--------------------------------------------------------------------------------
1 | const pluginCommonJS = require('@rollup/plugin-commonjs');
2 | const pluginVue = require('rollup-plugin-vue');
3 | const path = require('path');
4 |
5 | const purgeCSSOption = {
6 | content: ['./**/**/*.vue'],
7 |
8 | // This is the function used to extract class names from your templates
9 | defaultExtractor: content => {
10 | // Capture as liberally as possible, including things like `h-(screen-1.5)`
11 | const broadMatches = content.match(/[^<>"'`\s]*[^<>"'`\s:]/g) || [];
12 |
13 | // Capture classes within other delimiters like .block(class="w-1/2") in Pug
14 | const innerMatches =
15 | content.match(/[^<>"'`\s.()]*[^<>"'`\s.():]/g) || [];
16 |
17 | return broadMatches.concat(innerMatches);
18 | }
19 | };
20 |
21 | function plugins({ tailwind, purge } = { tailwind: false, purge: false }) {
22 | const postcssPlugins = _ => {
23 | return [
24 | require('postcss-import')(),
25 | require('postcss-url')(),
26 | tailwind && require('tailwindcss')(
27 | path.join(__dirname, '../tailwind.config.js')
28 | ),
29 | require('autoprefixer')(),
30 | purge && require('@fullhuman/postcss-purgecss')(purgeCSSOption),
31 | require('cssnano')({
32 | preset: 'default'
33 | })
34 | ].filter(Boolean);
35 | };
36 |
37 | const options = {
38 | defaultLang: { markdown: 'pluginMarkdown' },
39 | css: true,
40 | style: {
41 | postcssPlugins: postcssPlugins()
42 | }
43 | };
44 | return [pluginCommonJS(), pluginVue(options)];
45 | }
46 |
47 | export default plugins;
48 |
--------------------------------------------------------------------------------
/src/cli.js:
--------------------------------------------------------------------------------
1 | const start = Date.now();
2 |
3 | const argv = require('minimist')(process.argv.slice(2));
4 | const path = require('path');
5 | const chalk = require('chalk');
6 | const Fdir = require('fdir');
7 |
8 | import { resolvePaths, getDirectories, getVueFiles, normalizeBoolean } from './utils';
9 |
10 | import compileToHTML from './compile-to-html';
11 |
12 | function showHelp() {
13 | console.log(`
14 | Usage: vue2html [command] [path] [--options]
15 | Commands:
16 | vue2html [path] Convert vue component to html by default.
17 | vue2html component [path] Convert vue component to js component.
18 | Options:
19 | --help, -h [boolean] show help
20 | --version, -v [boolean] show version
21 | --tailwind [boolean] use tailwind plugin
22 | --purge [boolean] use purgecss
23 | --config, -c [string] use specified config file
24 | --base [string] public base path (default: /)
25 | --outDir=[name] [string] output directory (default: html_components)
26 | --template, -t [string] use specified server-renderer template.
27 | `);
28 | }
29 |
30 | console.log(chalk.cyan(`vue2html v${require('../package.json').version}`));
31 | (async () => {
32 | const { _: components, help, h, version, v, outDir, template, t, tailwind, purge } = argv;
33 |
34 | if (help || h) {
35 | showHelp();
36 | return;
37 | } else if (version || v) {
38 | return;
39 | }
40 |
41 | // Get all vue file paths
42 | const paths = getVueFiles(components);
43 | // Get all directory paths
44 | const dirs = getDirectories(components);
45 |
46 | if (dirs.length > 1) {
47 | dirs.forEach(dir => {
48 | // Create the builder
49 | const api = new Fdir()
50 | .glob('./**/*.vue')
51 | .withBasePath()
52 | .crawl(path.join(dir));
53 |
54 | // Get all files in a directory synchronously
55 | const files = api.sync();
56 |
57 | paths.push(...resolvePaths(files));
58 | });
59 | }
60 |
61 | // Start spinner
62 | await compileToHTML(paths.length === 1 ? paths[0] : paths, {
63 | context: {
64 | title: 'Title'
65 | },
66 | tailwind,
67 | purge,
68 | writeToFile: true,
69 | outDir,
70 | silent: false,
71 | template: template === undefined ? normalizeBoolean(t) : normalizeBoolean(template)
72 | });
73 |
74 | console.log(`Finished compiled in ${(Date.now() - start) / 1000}ms.`);
75 | })();
76 |
--------------------------------------------------------------------------------
/src/utils.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const fs = require('fs-extra');
3 |
4 | function isVueFile(path = '') {
5 | const re = /(.vue)+/;
6 | return re.test(path);
7 | }
8 |
9 | function getComponentName(path) {
10 | const re = /(\w+)(.vue+)/;
11 | return re.exec(path)[1];
12 | }
13 |
14 | function parseStrToFunc(code) {
15 | /* eslint-disable no-new-func */
16 | return new Function(code);
17 | /* eslint-enable no-new-func */
18 | }
19 |
20 | function convertSlash(path) {
21 | const isExtendedLengthPath = /^\\\\\?\\/.test(path);
22 | const hasNonAscii = /[^\u0000-\u0080]+/.test(path); // eslint-disable-line no-control-regex
23 |
24 | if (isExtendedLengthPath || hasNonAscii) {
25 | return path;
26 | }
27 |
28 | return path.replace(/\\/g, '/');
29 | }
30 |
31 | function getVueFiles(paths) {
32 | paths = paths.filter(p => {
33 | return path.extname(p) === '.vue';
34 | });
35 | return resolvePaths(paths);
36 | }
37 |
38 | function getDirectories(paths) {
39 | const dirs = [];
40 | paths.forEach(p => {
41 | if (path.extname(p) !== '.vue') {
42 | dirs.push(p);
43 | }
44 | });
45 | return resolvePaths(dirs);
46 | }
47 |
48 | function resolvePaths(paths) {
49 | paths = paths.map(p => {
50 | if (p[0] === '\\' || p[0] === '/') {
51 | p = p.slice(1);
52 | }
53 |
54 | return convertSlash(path.join(p));
55 | });
56 | return paths;
57 | }
58 |
59 | function isStringAndEmpty(val) {
60 | return typeof val === 'string' && val === '';
61 | }
62 |
63 | function normalizeBoolean(bool = '') {
64 | const b = bool.toLowerCase ? bool.toLowerCase() : bool;
65 | switch (b) {
66 | case 'true':
67 | return true;
68 | case 'false':
69 | return false;
70 | case true:
71 | case false:
72 | return b;
73 | default:
74 | return b;
75 | }
76 | }
77 |
78 | async function copyFirstComponent(components = []) {
79 | if (components.length === 0) {
80 | return components;
81 | }
82 |
83 | const firstC = components.shift();
84 |
85 | const firstCDir = path.dirname(firstC.resolvePath);
86 | const copyPath = path.join(firstCDir, '__copy__' + firstC.name + '.vue');
87 | await fs.copyFile(firstC.resolvePath, copyPath, err => {
88 | if (err) {
89 | throw err;
90 | }
91 | });
92 |
93 | firstC.path = convertSlash(
94 | path.join(path.dirname(firstC.path), '__copy__' + firstC.name + '.vue')
95 | );
96 | firstC.resolvePath = copyPath;
97 |
98 | components.unshift(firstC);
99 |
100 | return [components, convertSlash(copyPath)];
101 | }
102 |
103 | export {
104 | isVueFile,
105 | getComponentName,
106 | parseStrToFunc,
107 | convertSlash,
108 | resolvePaths,
109 | getDirectories,
110 | getVueFiles,
111 | isStringAndEmpty,
112 | normalizeBoolean,
113 | copyFirstComponent
114 | };
115 |
--------------------------------------------------------------------------------
/src/compile-to-html.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import compileToComponent from './compile-to-component';
3 | import { isStringAndEmpty } from './utils';
4 |
5 | const fs = require('fs-extra');
6 | const path = require('path');
7 |
8 | export default async function(filenames = '', options = {}) {
9 | if (!filenames) {
10 | return;
11 | }
12 |
13 | const componentHtmls = {};
14 | let renderer;
15 | let childSpinner = { stop: () => {}, start: () => {}, succeed: () => {} };
16 |
17 | // Extend default options
18 | const defaultOptions = {
19 | props: {},
20 | context: {},
21 | template: '',
22 | tailwind: false,
23 | purge: false,
24 | writeToFile: false,
25 | outDir: 'html_components',
26 | silent: true
27 | };
28 | Object.assign(defaultOptions, options);
29 |
30 | if (
31 | typeof defaultOptions.template !== 'boolean' ||
32 | defaultOptions.template
33 | ) {
34 | const templatePath =
35 | isStringAndEmpty(defaultOptions.template) ||
36 | defaultOptions.template === true
37 | ? path.resolve(__dirname, '../template', 'index.template.html')
38 | : defaultOptions.template;
39 | const template = await fs.readFile(templatePath, 'utf-8');
40 |
41 | renderer = require('vue-server-renderer').createRenderer({
42 | template,
43 | runInNewContext: true
44 | });
45 | } else {
46 | renderer = require('vue-server-renderer').createRenderer();
47 | }
48 |
49 | childSpinner = require('ora')('Compile to normalized component');
50 |
51 | childSpinner.start();
52 | const components = await compileToComponent(filenames, defaultOptions);
53 | childSpinner.stop();
54 |
55 | // Make sure output directory exists
56 | const outDirname = defaultOptions.outDir || 'html_components';
57 | await fs.ensureDir(outDirname);
58 | // Loop trough components and render them to html
59 | Object.keys(components).forEach((key, idx) => {
60 | childSpinner.start(`Compiling ${key} component to HTML...`);
61 | let component = components[key];
62 |
63 | // This is needed because when filenames is Array
64 | // all the property needed are inside default property.
65 | if (component.default) {
66 | component = component.default;
67 | }
68 |
69 | const props = Array.isArray(filenames)
70 | ? defaultOptions.props[idx]
71 | : defaultOptions.props;
72 |
73 | const vueInstance = new Vue({
74 | render: h => h(component, { props })
75 | });
76 |
77 | renderer.renderToString(
78 | vueInstance,
79 | defaultOptions.context,
80 | async (err, html) => {
81 | if (err) {
82 | throw err;
83 | }
84 |
85 | componentHtmls[key] = html;
86 |
87 | if (defaultOptions.writeToFile) {
88 | const filename = key + '.html';
89 | await fs.writeFile(path.join(outDirname, filename), html);
90 | }
91 | }
92 | );
93 | childSpinner.succeed(`Success compiling ${key} component`);
94 | });
95 |
96 | return componentHtmls;
97 | }
98 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue2html",
3 | "description": "A simple tool to convert vue component to html ",
4 | "version": "0.2.1",
5 | "author": "Muhammad Athif Humam (https://athif23.github.io/)",
6 | "bugs": {
7 | "url": "https://github.com/athif23/vue2html/issues",
8 | "email": "emailta.indo@gmail.com"
9 | },
10 | "commitlint": {
11 | "extends": [
12 | "@commitlint/config-conventional"
13 | ]
14 | },
15 | "contributors": [
16 | "Muhammad Athif Humam (https://athif23.github.io/)"
17 | ],
18 | "bin": {
19 | "vue2html": "bin/cli.js"
20 | },
21 | "files": [
22 | "dist/**/*.js",
23 | "bin",
24 | "template",
25 | "tailwind.config.js"
26 | ],
27 | "dependencies": {
28 | "@fullhuman/postcss-purgecss": "^2.2.0",
29 | "@rollup/plugin-alias": "^3.1.0",
30 | "@rollup/plugin-commonjs": "^12.0.0",
31 | "@rollup/plugin-node-resolve": "^8.0.0",
32 | "autoprefixer": "^9.8.0",
33 | "chalk": "^4.0.0",
34 | "cssnano": "^4.1.10",
35 | "fdir": "^3.4.2",
36 | "fs-extra": "^9.0.0",
37 | "minimist": "^1.2.5",
38 | "ora": "^4.0.4",
39 | "postcss": "^7.0.32",
40 | "postcss-assets": "^5.0.0",
41 | "postcss-import": "^12.0.1",
42 | "postcss-url": "^8.0.0",
43 | "replace-in-file": "^6.0.0",
44 | "rollup": "^2.12.0",
45 | "rollup-plugin-gzip": "^2.5.0",
46 | "rollup-plugin-postcss": "^3.1.1",
47 | "rollup-plugin-terser": "^6.1.0",
48 | "rollup-plugin-vue": "^5.1.9",
49 | "tailwindcss": "^1.4.6",
50 | "vue": "^2.6.11",
51 | "vue-server-renderer": "^2.6.11",
52 | "vue-template-compiler": "^2.6.11"
53 | },
54 | "devDependencies": {
55 | "@commitlint/cli": "latest",
56 | "@commitlint/config-conventional": "latest",
57 | "ava": "latest",
58 | "codecov": "latest",
59 | "cross-env": "latest",
60 | "eslint": "6.x",
61 | "eslint-config-xo-lass": "latest",
62 | "fixpack": "latest",
63 | "husky": "latest",
64 | "lint-staged": "latest",
65 | "nyc": "latest",
66 | "remark-cli": "latest",
67 | "remark-preset-github": "latest",
68 | "xo": "0.25"
69 | },
70 | "engines": {
71 | "node": ">=8.3"
72 | },
73 | "homepage": "https://github.com/athif23/vue2html",
74 | "husky": {
75 | "hooks": {
76 | "commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
77 | }
78 | },
79 | "keywords": [
80 | "converter",
81 | "html",
82 | "tool",
83 | "vue"
84 | ],
85 | "license": "MIT",
86 | "main": "src/index.js",
87 | "prettier": {
88 | "singleQuote": true,
89 | "bracketSpacing": true,
90 | "trailingComma": "none"
91 | },
92 | "remarkConfig": {
93 | "plugins": [
94 | "preset-github"
95 | ]
96 | },
97 | "repository": {
98 | "type": "git",
99 | "url": "https://github.com/athif23/vue2html"
100 | },
101 | "scripts": {
102 | "ava": "cross-env NODE_ENV=test ava",
103 | "coverage": "nyc report --reporter=text-lcov > coverage.lcov && codecov",
104 | "lint": "xo && remark . -qfo",
105 | "nyc": "cross-env NODE_ENV=test nyc ava",
106 | "test": "npm run lint && npm run ava",
107 | "test-coverage": "npm run lint && npm run nyc",
108 | "build": "rollup -c",
109 | "watch": "rollup -c -w"
110 | },
111 | "xo": {
112 | "prettier": false,
113 | "space": 4,
114 | "rules": {
115 | "object-curly-spacing": "off",
116 | "operator-linebreak": "off",
117 | "space-before-function-paren": "off",
118 | "no-else-return": "off",
119 | "import/no-unassigned-import": "off",
120 | "ava/use-t": "off",
121 | "no-unused-expressions": "off"
122 | }
123 | }
124 | }
125 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue2html
2 |
3 | [](https://travis-ci.com/athif23/vue2html)
4 | [](https://codecov.io/gh/athif23/vue2html)
5 | [](https://github.com/sindresorhus/xo)
6 | [](https://github.com/prettier/prettier)
7 | [](https://lass.js.org)
8 | [](LICENSE)
9 | [](https://npm.im/vue2html)
10 |
11 | > A simple tool to convert vue component to html
12 |
13 | > DISCLAIMER: This library are still in development, so there's many missing features.
14 |
15 |
16 | ## Table of Contents
17 |
18 | * [Install](#install)
19 | * [Usage](#usage)
20 | * [Options](#options)
21 | * [Contributors](#contributors)
22 | * [Known Issues](#known-issues)
23 | * [License](#license)
24 |
25 |
26 | ## Install
27 |
28 | Install `vue2html` globally,
29 |
30 | ```sh
31 | npm install -g vue2html
32 | ```
33 |
34 | ## Usage
35 |
36 | Now, you just need to pass your `.vue` file as the argument. You can pass as much as you want. Directory or Components paths.
37 |
38 | ```sh
39 | vue2html Component.vue App.vue ./components
40 | ```
41 |
42 | Use `--help` or `-h` to see all the available options.
43 | ```sh
44 | vue2html --help
45 | ```
46 |
47 | Or you can also call it programmatically.
48 |
49 | ```sh
50 | npm install vue2html
51 | ```
52 |
53 | ```js
54 | const { compileToHTML } = require('vue2html');
55 | const path = require('path');
56 |
57 | // Single path
58 | compileToHTML('./Component.vue', {
59 | props: {},
60 | // Pass vue-server-renderer's `context`
61 | context: {
62 | title: 'vue ssr',
63 | metas: `
64 |
65 |
66 | `,
67 | },
68 | writeToFile: true
69 | });
70 |
71 | // Multiple paths
72 | compileToHTML(['./Component.vue', './Header.vue'], {
73 | // Note: the order of the props need to be the same with the order of the paths
74 | props: [
75 | { name: "Athif Humam", count: 12 },
76 | { color: 'black' }
77 | ],
78 | writeToFile: true
79 | });
80 | ```
81 |
82 | ### Known Issues
83 | * If you use tailwind please remember that it would take more time to generate than without it, especially if you also use purge option. I mean that's just how it should be. I can't change it even if I want to.
84 |
85 | * Component's style included in other components. I don't know why this happens, and I honestly doesn't really want to care much about this right now. But don't worry if you use scoped style, it would be safe even if it included in other components... I think.
86 |
87 | ##### TODO
88 |
89 | * [x] Add css
90 | * [x] Add postcss plugins
91 | * [x] Add Tailwindcss
92 | * [x] Can pass folder path as an argument, like `./components`
93 | * [ ] Add more test
94 | * [ ] Convert raw string instead of file
95 |
96 | > I haven't found a way to do this yet, and as far as I know, rollup only allowed file path to be passed to their input options. If someone know about this, please do tell me or you can just open up a PR. I would really appreciate it :)
97 |
98 |
99 | ## Contributors
100 |
101 | | Name | Website |
102 | | ------------------------ | ---------------------------- |
103 | | **Muhammad Athif Humam** | |
104 |
105 |
106 | ## License
107 |
108 | [MIT](LICENSE) © [Muhammad Athif Humam](https://athif23.github.io/)
109 |
--------------------------------------------------------------------------------
/src/compile-to-component.js:
--------------------------------------------------------------------------------
1 | import plugins from './plugins';
2 | import {
3 | isVueFile,
4 | getComponentName,
5 | parseStrToFunc,
6 | convertSlash,
7 | copyFirstComponent
8 | } from './utils';
9 |
10 | const { rollup } = require('rollup');
11 | const path = require('path');
12 | const fs = require('fs-extra');
13 |
14 | export default async function(filenames, options = {}) {
15 | if (!filenames) {
16 | return;
17 | }
18 |
19 | let vueComponents;
20 | let imports = '';
21 |
22 | // This is default options
23 | const defaultOptions = {
24 | props: {},
25 | plugins: [],
26 | tailwind: false,
27 | purge: false
28 | };
29 |
30 | // Extend default options
31 | Object.assign(defaultOptions, options);
32 |
33 | if (Array.isArray(filenames)) {
34 | vueComponents = filenames.map(file => {
35 | return {
36 | name: getComponentName(file),
37 | isVue: isVueFile(file),
38 | path: convertSlash(
39 | path.relative(path.resolve(__dirname, '../template'), file)
40 | ),
41 | resolvePath: path.resolve(file)
42 | };
43 | });
44 | } else {
45 | const component = {
46 | name: getComponentName(filenames),
47 | isVue: isVueFile(filenames),
48 | path: convertSlash(
49 | path.relative(path.resolve(__dirname, '../template'), filenames)
50 | ),
51 | resolvePath: path.resolve(filenames)
52 | };
53 | vueComponents = [component];
54 | }
55 |
56 | let copyResult;
57 | if (defaultOptions.tailwind) {
58 | copyResult = await copyFirstComponent(vueComponents);
59 |
60 | vueComponents = copyResult[0];
61 |
62 | // I don't know why, but it runs fine with this line.
63 | setTimeout(() => {}, 500);
64 |
65 | const replace = require('replace-in-file');
66 | await replace({
67 | files: path.resolve(vueComponents[0].resolvePath),
68 | from: /