Skip to content
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

feat: add SFC support #7

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions template/base/package.json.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
"@babel/core": "^7.24.7",
"@babel/plugin-transform-runtime": "^7.24.7",
"@babel/preset-env": "^7.24.7",
"vue": "^3.4.31",
<%_ if (needsTypeScript) { _%>
"@babel/preset-typescript": "^7.24.7",
<%_ } _%>
Expand Down
119 changes: 106 additions & 13 deletions template/javascript/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import replace from '@rollup/plugin-replace';
import terser from '@rollup/plugin-terser';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { parse as templateParse } from 'vue/compiler-sfc';

const NODE_ENV = process.env.NODE_ENV || 'production';
const __PROD__ = NODE_ENV === 'production';
Expand All @@ -23,6 +24,17 @@ const terserOptions = {
format: { comments: false },
};

/**
* Ensure the file exists by creating the directory if it doesn't exist.
* @param {string} filePath
*/
async function ensureFileExists(filePath) {
const isFileExists = await fs.exists(filePath);
if (!isFileExists) {
await fs.mkdir(path.dirname(filePath), { recursive: true });
}
}

const bundledModules = new Set();
async function bundleModule(module) {
if (bundledModules.has(module)) return;
Expand All @@ -49,12 +61,26 @@ async function bundleModule(module) {
});
}

async function processScript(filePath) {
/**
* Process the script file.
* If the script is not provided, the file will be read from the file system.
* @param {string} filePath
* @param {string | undefined} script
*/
async function processScript(filePath, script) {
let ast, code;
try {
const result = await babel.transformFileAsync(path.resolve(filePath), {
ast: true,
});
let result;
if (script) {
result = await babel.transformAsync(script, {
ast: true,
filename: path.resolve(filePath),
});
} else {
result = await babel.transformFileAsync(path.resolve(filePath), {
ast: true,
});
}
ast = result.ast;
code = result.code;
} catch (error) {
Expand Down Expand Up @@ -101,19 +127,44 @@ async function processScript(filePath) {

const destination = filePath.replace('src', 'dist');
// Make sure the directory already exists when write file
await fs.copy(filePath, destination);
await ensureFileExists(destination);
fs.writeFile(destination, code);
}

async function processTemplate(filePath) {
const destination = filePath
.replace('src', 'dist')
.replace(/\.html$/, '.wxml');
await fs.copy(filePath, destination);
/**
* Process the template file.
* If the template is not provided, the file will be read from the file system.
* @param {string} filePath
* @param {string} template
*/
async function processTemplate(filePath, template) {

if (template) {
await ensureFileExists(filePath);
await fs.writeFile(filePath, template);
} else {
const destination = filePath
.replace('src', 'dist')
.replace(/\.html$/, '.wxml');
await fs.copy(filePath, destination);
}


}

/**
* Process the style file.
* If the style is not provided, the file will be read from the file system.
* @param {string} filePath
*/
async function processStyle(filePath) {
const source = await fs.readFile(filePath, 'utf8');

let source;
if (style) {
source = style;
} else {
source = await fs.readFile(filePath, 'utf8');
}
const { plugins, options } = await postcssrc({ from: undefined });

let css;
Expand All @@ -132,14 +183,50 @@ async function processStyle(filePath) {
const destination = filePath
.replace('src', 'dist')
.replace(/\.css$/, '.wxss');
// Make sure the directory already exists when write file
await fs.copy(filePath, destination);
ensureFileExists(destination);
fs.writeFile(destination, css);
}

/**
* Process the Single File Component (SFC) file.
* The file will be read from the file system.
* The script, template, and style will be extracted from the SFC file.
* now do not support scoped style
* and only support one style block
* @param {string} filePath
*/
function processSFC(filePath) {
const source = fs.readFileSync(filePath, 'utf8');
const parsedSrc = templateParse(source);
const script = parsedSrc.descriptor.script.content;
const scriptLang = parsedSrc.descriptor.script.lang;
const template = parsedSrc.descriptor.template.content;
const style = parsedSrc.descriptor.styles[0];

const virtualScriptPath = filePath
.replace('src', 'dist')
.replace(/\.vue$/, `.${scriptLang}`);
const virtualTemplatePath = filePath
.replace('src', 'dist')
.replace(/\.vue$/, '.wxml');
const virtualStylePaths = filePath
.replace('src', 'dist')
.replace(/\.vue$/, '.css');

processScript(virtualScriptPath, script);
processTemplate(virtualTemplatePath, template);
processStyle(virtualStylePaths, style.content);
}

async function dev() {
await fs.remove('dist');
const cb = (filePath) => {

if (/\.vue$/.test(filePath)) {
processSFC(filePath);
return;
}

if (/\.js$/.test(filePath)) {
processScript(filePath);
return;
Expand Down Expand Up @@ -176,6 +263,12 @@ async function prod() {
ignored: ['**/.{gitkeep,DS_Store}'],
});
watcher.on('add', (filePath) => {

if (/\.vue$/.test(filePath)) {
processSFC(filePath);
return;
}

if (/\.js$/.test(filePath)) {
processScript(filePath);
return;
Expand Down
116 changes: 102 additions & 14 deletions template/typescript/build.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import replace from '@rollup/plugin-replace';
import terser from '@rollup/plugin-terser';
import resolve from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import { parse as templateParse } from 'vue/compiler-sfc';

const NODE_ENV = process.env.NODE_ENV || 'production';
const __PROD__ = NODE_ENV === 'production';
Expand All @@ -23,6 +24,17 @@ const terserOptions = {
format: { comments: false },
};

/**
* Ensure the file exists by creating the directory if it doesn't exist.
* @param {string} filePath
*/
async function ensureFileExists(filePath) {
const isFileExists = await fs.exists(filePath);
if (!isFileExists) {
await fs.mkdir(path.dirname(filePath), { recursive: true });
}
}

const bundledModules = new Set();
async function bundleModule(module) {
if (bundledModules.has(module)) return;
Expand All @@ -49,12 +61,26 @@ async function bundleModule(module) {
});
}

async function processScript(filePath) {
/**
* Process the script file.
* If the script is not provided, the file will be read from the file system.
* @param {string} filePath
* @param {string | undefined} script
*/
async function processScript(filePath, script) {
let ast, code;
try {
const result = await babel.transformFileAsync(path.resolve(filePath), {
ast: true,
});
let result;
if (script) {
result = await babel.transformAsync(script, {
ast: true,
filename: path.resolve(filePath),
});
} else {
result = await babel.transformFileAsync(path.resolve(filePath), {
ast: true,
});
}
ast = result.ast;
code = result.code;
} catch (error) {
Expand Down Expand Up @@ -101,19 +127,41 @@ async function processScript(filePath) {

const destination = filePath.replace('src', 'dist').replace(/\.ts$/, '.js');
// Make sure the directory already exists when write file
await fs.copy(filePath, destination);
await ensureFileExists(destination);
fs.writeFile(destination, code);
}

async function processTemplate(filePath) {
const destination = filePath
.replace('src', 'dist')
.replace(/\.html$/, '.wxml');
await fs.copy(filePath, destination);
/**
* Process the template file.
* If the template is not provided, the file will be read from the file system.
* @param {string} filePath
* @param {string} template
*/
async function processTemplate(filePath, template) {
if (template) {
await ensureFileExists(filePath);
await fs.writeFile(filePath, template);
} else {
const destination = filePath
.replace('src', 'dist')
.replace(/\.html$/, '.wxml');
await fs.copy(filePath, destination);
}
}

async function processStyle(filePath) {
const source = await fs.readFile(filePath, 'utf8');
/**
* Process the style file.
* If the style is not provided, the file will be read from the file system.
* @param {string} filePath
* @param {string} style
*/
async function processStyle(filePath, style) {
let source;
if (style) {
source = style;
} else {
source = await fs.readFile(filePath, 'utf8');
}
const { plugins, options } = await postcssrc({ from: undefined });

let css;
Expand All @@ -132,14 +180,49 @@ async function processStyle(filePath) {
const destination = filePath
.replace('src', 'dist')
.replace(/\.css$/, '.wxss');
// Make sure the directory already exists when write file
await fs.copy(filePath, destination);
ensureFileExists(destination);
fs.writeFile(destination, css);
}

/**
* Process the Single File Component (SFC) file.
* The file will be read from the file system.
* The script, template, and style will be extracted from the SFC file.
* now do not support scoped style
* and only support one style block
* @param {string} filePath
*/
function processSFC(filePath) {
const source = fs.readFileSync(filePath, 'utf8');
const parsedSrc = templateParse(source);
const script = parsedSrc.descriptor.script.content;
const scriptLang = parsedSrc.descriptor.script.lang;
const template = parsedSrc.descriptor.template.content;
const style = parsedSrc.descriptor.styles[0];

const virtualScriptPath = filePath
.replace('src', 'dist')
.replace(/\.vue$/, `.${scriptLang}`);
const virtualTemplatePath = filePath
.replace('src', 'dist')
.replace(/\.vue$/, '.wxml');
const virtualStylePaths = filePath
.replace('src', 'dist')
.replace(/\.vue$/, '.css');

processScript(virtualScriptPath, script);
processTemplate(virtualTemplatePath, template);
processStyle(virtualStylePaths, style.content);
}

async function dev() {
await fs.remove('dist');
const cb = (filePath) => {
if (/\.vue$/.test(filePath)) {
processSFC(filePath);
return;
}

if (/\.ts$/.test(filePath)) {
processScript(filePath);
return;
Expand Down Expand Up @@ -176,6 +259,11 @@ async function prod() {
ignored: ['**/.{gitkeep,DS_Store}'],
});
watcher.on('add', (filePath) => {
if (/\.vue$/.test(filePath)) {
processSFC(filePath);
return;
}

if (/\.ts$/.test(filePath)) {
processScript(filePath);
return;
Expand Down