Skip to content

Commit d4e6c95

Browse files
committed
fix: native url transform in both template and style
1 parent c248ebf commit d4e6c95

File tree

14 files changed

+423
-324
lines changed

14 files changed

+423
-324
lines changed

package.json

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,16 @@
2020
"url": "git@github.com:b2nil/vminiBuild.git"
2121
},
2222
"scripts": {
23-
"dev": "esbuild src/index.ts --outfile=dist/index.js --format=cjs --platform=node --tree-shaking=true --external:esbuild --external:url --external:pug --external:postcss-pxtransform --external:@vue/* --bundle",
23+
"dev": "esbuild src/index.ts --outfile=dist/index.js --format=cjs --platform=node --tree-shaking=true --external:esbuild --external:url --external:pug --external:postcss-pxtransform --external:postcss-url --external:@vue/* --bundle",
2424
"build": "yarn dev --minify",
25-
"plugin": "esbuild src/plugins/index.ts --outfile=tests/plugin.js --format=cjs --platform=node --tree-shaking=true --external:esbuild --external:url --external:pug --external:postcss-pxtransform --external:@vue/* --bundle",
25+
"plugin": "esbuild src/plugins/index.ts --outfile=tests/plugin.js --format=cjs --platform=node --tree-shaking=true --external:esbuild --external:url --external:pug --external:postcss-pxtransform --external:postcss-url --external:@vue/* --bundle",
2626
"test": "yarn plugin && jest"
2727
},
2828
"peerDependencies": {
2929
"@vue/compiler-sfc": "^3.2.31",
30-
"esbuild": "^0.14.21"
30+
"esbuild": "^0.14.21",
31+
"postcss-pxtransform": "^3.4.2",
32+
"postcss-url": "^10.1.3"
3133
},
3234
"dependencies": {
3335
"cac": "^6.7.12"
@@ -42,4 +44,4 @@
4244
"jest": "^27.5.1",
4345
"postcss-modules": "^4.3.0"
4446
}
45-
}
47+
}

readme.md

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -293,14 +293,9 @@
293293
- [ ] style bindings
294294
- [ ] class bindings
295295
- [ ] native page and components bundling
296-
- [x] native template asset url transform
297296
- [ ] components
298297
- [ ] third party libs
299298
- [ ] cache module name for bundling to `miniprogram_npm`
300-
- [ ] style
301-
- [ ] postcss transform
302-
- [ ] serve url locally if `useCDN` is enabled
303-
- [ ] or convert url to base64 if not
304299
- [ ] mini-app tag.d.ts for volar syntax highlighting
305300

306301
## 关于 `vue-mini`

src/compiler-mini/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export { compileScript } from "./script"
2-
export { compileTemplate, normalizeAssetsURLOptions, getPlatformDirective } from "./template"
2+
export { compileTemplate, getPlatformDirective } from "./template"
33
export { parse, compileStyleAsync } from "@vue/compiler-sfc"

src/compiler-mini/template/index.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ function preprocess (
4343
}
4444

4545
export { getPlatformDirective } from "./utils"
46-
export { normalizeAssetsURLOptions } from "./transforms"
4746

4847
export async function compileTemplate (
4948
template: string,

src/compiler-mini/template/transforms/assetUrls.ts

Lines changed: 9 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,18 @@
11
import path from 'path'
2-
import { isString } from '@vue/shared'
3-
import { UrlWithStringQuery, parse as uriParse } from 'url'
2+
import {
3+
parseUrl,
4+
isDataUrl,
5+
isExternalUrl,
6+
isRelativeUrl,
7+
normalizeAssetsURLOptions,
8+
} from '../../../utils'
49

510
import {
611
NodeTypes,
712
NodeTransform,
813
createSimpleExpression,
914
} from '@vue/compiler-core'
15+
1016
import type {
1117
AssetURLOptions,
1218
AssetURLTagConfig
@@ -99,56 +105,4 @@ export function transformAssetUrls (
99105
})
100106
}
101107
}
102-
}
103-
104-
// The following util functions are copied
105-
// from @vue/compiler-sfc's templateUtils.ts
106-
// since they are exposed to external users
107-
const dataUrlRE = /^\s*data:/i
108-
const externalRE = /^(https?:)?\/\//
109-
const isDataUrl = (url: string) => dataUrlRE.test(url)
110-
const isExternalUrl = (url: string) => externalRE.test(url)
111-
112-
const isRelativeUrl = (url: string): boolean => {
113-
const firstChar = url.charAt(0)
114-
return firstChar === '.' || firstChar === '~' || firstChar === '@'
115-
}
116-
117-
export function normalizeAssetsURLOptions (
118-
options: AssetURLOptions | AssetURLTagConfig,
119-
defaultOptions: Required<AssetURLOptions>
120-
): Required<AssetURLOptions> {
121-
if (Object.keys(options).some(key => Array.isArray((options as any)[key]))) {
122-
// legacy option format which directly passes in tags config
123-
return {
124-
...defaultOptions,
125-
tags: options as any
126-
}
127-
}
128-
return {
129-
...defaultOptions,
130-
...options
131-
}
132-
}
133-
134-
/**
135-
* Parses string url into URL object.
136-
*/
137-
function parseUrl (url: string): UrlWithStringQuery {
138-
const firstChar = url.charAt(0)
139-
if (firstChar === '~') {
140-
const secondChar = url.charAt(1)
141-
url = url.slice(secondChar === '/' ? 2 : 1)
142-
}
143-
return parseUriParts(url)
144-
}
145-
146-
/**
147-
* vuejs/component-compiler-utils#22 Support uri fragment in transformed require
148-
* @param urlString an url as a string
149-
*/
150-
function parseUriParts (urlString: string): UrlWithStringQuery {
151-
// A TypeError is thrown if urlString is not a string
152-
// @see https://nodejs.org/api/url.html#url_url_parse_urlstring_parsequerystring_slashesdenotehost
153-
return uriParse(isString(urlString) ? urlString : '', false, true)
154-
}
108+
}

src/index.ts

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import {
77
DEFINE,
88
customRequire,
99
extractConfigFromFile,
10+
normalizeAssetsURLOptions
1011
} from './utils'
1112
import {
1213
printStats,
@@ -18,7 +19,6 @@ import {
1819

1920
import type { BuildOptions } from "esbuild"
2021
import type { UserConfig, CliOptions } from 'types'
21-
import { normalizeAssetsURLOptions } from './compiler-mini'
2222

2323
const cli = cac("vmini")
2424

@@ -89,15 +89,13 @@ async function initBuildOptions (userConfig: UserConfig): Promise<BuildOptions>
8989
useCDN,
9090
style: {
9191
...(userBuildOptions.vue?.style || {}),
92-
postcssPlugins:
93-
userBuildOptions.vue?.style?.postcssPlugins
94-
? userBuildOptions.vue?.style?.postcssPlugins
95-
: [
96-
customRequire(`postcss-pxtransform`)({
97-
platform: userBuildOptions.platform || `weapp`,
98-
designWidth: userBuildOptions.designWidth || 750
99-
})
100-
],
92+
postcssPlugins: [
93+
...(userBuildOptions.vue?.style?.postcssPlugins || []),
94+
customRequire(`postcss-pxtransform`)({
95+
platform: userBuildOptions.platform || `weapp`,
96+
designWidth: userBuildOptions.designWidth || 750
97+
})
98+
],
10199
preprocessCustomRequire: customRequire
102100
},
103101
template: {

src/plugins/native.ts

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import {
1313
parseVueRequest,
1414
getRegExpMatchedCode,
1515
getNativeImportsHelperCode,
16+
cacheAssetPath,
1617
} from "../utils"
1718
import {
1819
compileTemplate,
@@ -136,24 +137,35 @@ export default function nativePlugin (options: VueOptions = {}): Plugin {
136137

137138
build.onLoad({ filter: /.*/, namespace: "native-wxml" }, async (args) => {
138139
const filename = args.path
139-
let nativeTemplate = await fs.promises.readFile(filename, "utf8")
140+
const nativeTemplate = await fs.promises.readFile(filename, "utf8")
140141
const importsCode = getRegExpMatchedCode(nativeTemplate, wxsSrcREG)
141142

142-
// should transform asset urls if useCDN
143-
if (options.useCDN) {
144-
const platformDir = getPlatformDirective(process.env.__PLATFORM__ || "weapp")
145-
const ret = await compileTemplate(nativeTemplate, {
146-
...(options),
147-
filename,
148-
id: "wxml",
149-
cssVars: [],
150-
cssModules: {},
151-
platformDir
152-
})
153-
nativeTemplate = ret.code
143+
const platformDir = getPlatformDirective(process.env.__PLATFORM__ || "weapp")
144+
let { code: templateCode, ast, errors } = await compileTemplate(nativeTemplate, {
145+
...(options.template || {}),
146+
filename,
147+
id: "wxml",
148+
cssVars: [],
149+
cssModules: {},
150+
platformDir
151+
})
152+
153+
if (errors.length) {
154+
templateCode = ``
155+
for (const err of errors) {
156+
console.warn(`[x] ${err}`)
157+
}
158+
}
159+
160+
// cache asset urls used
161+
if (ast?.imports && !options.useCDN) {
162+
for (const imp of ast.imports) {
163+
const assetPath = path.resolve(path.dirname(filename), imp.path)
164+
cacheAssetPath(assetPath)
165+
}
154166
}
155167

156-
await emitFile(filename, EXTENSIONS.WXML, nativeTemplate)
168+
await emitFile(filename, EXTENSIONS.WXML, templateCode)
157169

158170
return {
159171
contents: importsCode,

src/plugins/style.ts

Lines changed: 28 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,14 @@
11
import path from "path"
22
import fs from "fs"
3-
import { cssREG, getFullPath, replaceRules } from "../utils"
43
import { compileStyleAsync } from "../compiler-mini"
4+
import {
5+
cssREG,
6+
getFullPath,
7+
genPreprocessOptions,
8+
customRequire,
9+
genPostcssUrlOptions
10+
} from "../utils"
11+
512
import type { Plugin } from "esbuild"
613
import type { VueOptions } from 'types'
714

@@ -27,39 +34,42 @@ export default function styleLoader (options: VueOptions = {}): Plugin {
2734
build.onLoad({ filter: /.*/, namespace: "styles" }, async (args) => {
2835
const { path: filename, pluginData: { lang } } = args
2936
const source = await fs.promises.readFile(filename, "utf8")
37+
const deps = new Set<string>([])
3038
const res = await compileStyleAsync({
3139
source,
3240
filename,
3341
id: "stylefile",
3442
preprocessLang: lang as any,
35-
preprocessOptions: {
36-
includePaths: [
37-
path.dirname(filename),
38-
"src/styles",
39-
"node_modules"
40-
],
41-
importer: [
42-
(url: string) => {
43-
const file = replaceRules(url)
44-
const modulePath = path.join(process.cwd(), "node_modules", file)
45-
if (fs.existsSync(modulePath)) return { file: modulePath }
46-
return { file }
47-
}
48-
],
49-
...(options?.style?.preprocessOptions || {})
50-
},
43+
preprocessOptions: genPreprocessOptions(
44+
filename,
45+
options?.style?.preprocessOptions
46+
),
47+
postcssPlugins: [
48+
...(options?.style?.postcssPlugins || []),
49+
customRequire(`postcss-url`)({
50+
url: !options.useCDN ? "inline" : genPostcssUrlOptions(options)
51+
})
52+
],
5153
...(options?.style || {})
5254
})
5355

5456
if (res.errors.length) {
5557
console.warn(res.errors.map((e) => `${e}`).join("\n"))
5658
}
5759

60+
if (res.dependencies.size) {
61+
Array
62+
.from(res.dependencies)
63+
.map(d => {
64+
if (!deps.has(d) && !d.startsWith(".vue")) deps.add(d)
65+
})
66+
}
67+
5868
return {
5969
contents: res.code,
6070
resolveDir: path.dirname(args.path),
6171
loader: "css",
62-
watchFiles: [args.path]
72+
watchFiles: [args.path, ...Array.from(deps)]
6373
}
6474
})
6575
}

0 commit comments

Comments
 (0)