-
Notifications
You must be signed in to change notification settings - Fork 33
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge remote-tracking branch 'origin/master' into docs
- Loading branch information
Showing
28 changed files
with
489 additions
and
121 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,89 @@ | ||
import { existsSync } from 'fs' | ||
import { extname, dirname, basename, relative, resolve } from 'path' | ||
import { createDistTransformPlugin } from './create-dist-transform' | ||
|
||
const parsePath = (path: string) => { | ||
const ext = extname(path).replace('.', '') | ||
|
||
return { | ||
ext, | ||
dir: dirname(path), | ||
name: basename(path, `.${ext}`), | ||
} | ||
} | ||
|
||
/** | ||
* Checks if file is Vuestic component template source | ||
* If file is script source, but there is not template then add css to script. | ||
* Component usually have script which is stored in file with name like Va[ComponentName].vue_vue_type_script_lang | ||
* | ||
* @notice Component can have render function without template block. It also can have only template without script block. | ||
*/ | ||
const isComponent = (filename: string) => { | ||
// [ComponentName].vue_vue_type_script_lang.mjs | ||
// [ComponentName].vue_vue_type_script_setup_true_lang.mjs | ||
const isScriptFile = /\w*.vue_vue_type_script\w*_lang.m?js$/.test(filename) | ||
if (isScriptFile) { | ||
return true | ||
} | ||
|
||
// Va[ComponentName].mjs | ||
const isTemplateFile = /\w*\.m?js$/.test(filename) | ||
|
||
// Va[ComponentName].vue_vue_type_script_lang.mjs | ||
const scriptFilePath = filename.replace(/\.(mjs|js)/, '.vue_vue_type_script_lang.mjs') | ||
const scriptSetupFilePath = filename.replace(/\.(mjs|js)/, '.vue_vue_type_script_setup_true_lang.mjs') | ||
|
||
const haveScript = existsSync(scriptFilePath) || existsSync(scriptSetupFilePath) | ||
|
||
if (isTemplateFile && !haveScript) { | ||
return true | ||
} | ||
|
||
return false | ||
} | ||
|
||
const extractVuesticComponentName = (filename: string) => { | ||
return filename.match(/(\w*)/)?.[1] | ||
} | ||
|
||
const SOURCE_MAP_COMMENT_FRAGMENT = '//# sourceMappingURL=' | ||
|
||
const appendBeforeSourceMapComment = (content: string, append: string): string => { | ||
return content.replace(SOURCE_MAP_COMMENT_FRAGMENT, `${append}\n${SOURCE_MAP_COMMENT_FRAGMENT}`) | ||
} | ||
|
||
export const appendComponentCss = createDistTransformPlugin({ | ||
name: 'vuestic:append-component-css', | ||
|
||
dir: (outDir) => `${outDir}/src/components`, | ||
|
||
transform (componentContent, path) { | ||
if (!isComponent(path)) { return } | ||
|
||
const { name, dir } = parsePath(path) | ||
|
||
const componentName = extractVuesticComponentName(name) | ||
|
||
if (!componentName) { | ||
throw new Error(`Can't extract component name from ${name}`) | ||
} | ||
|
||
const distPath = resolve(this.outDir, '..', '..') | ||
const relativeDistPath = relative(dir, distPath) | ||
const relativeFilePath = relativeDistPath + '/' + componentName.replace(/-.*$/, '') + '.css' | ||
|
||
// There are few cases how vite can store css files (depends on vite version, but we handle both for now): | ||
// CSS stored in dist folder (root) | ||
if (existsSync(resolve(dir, relativeFilePath))) { | ||
return appendBeforeSourceMapComment(componentContent, `\nimport '${relativeFilePath}';`) | ||
} | ||
|
||
// CSS stored in component folder | ||
const cssFilePath = `${dir}/${componentName}.css` | ||
|
||
if (existsSync(cssFilePath)) { | ||
return appendBeforeSourceMapComment(componentContent, `\nimport './${componentName}.css';`) | ||
} | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
/** | ||
* Inspired by VuesticUI build config | ||
* https://github.com/epicmaxco/vuestic-ui/blob/develop/packages/ui/build/common-config.ts | ||
*/ | ||
import { readFileSync, lstatSync, readdirSync } from 'fs' | ||
import vue from '@vitejs/plugin-vue' | ||
import { UserConfig } from 'vite' | ||
import { resolve as resolver } from 'path' | ||
import { chunkSplitPlugin } from 'vite-plugin-chunk-split' | ||
import { removeSideEffectedChunks } from './remove-side-effect-chunks' | ||
import { fixVueGenericComponentFileNames } from './fix-generic-file-names' | ||
import { appendComponentCss } from './append-component-css' | ||
import { generateScopedName } from '../namespaced-classname.js'; | ||
import svgLoader from 'vite-svg-loader'; | ||
import { replaceCodePlugin } from 'vite-plugin-replace'; | ||
import dts from 'vite-plugin-dts'; | ||
|
||
export const defineViteConfig = <T extends UserConfig>(p: T): UserConfig & T => p | ||
|
||
import type { RollupOptions } from 'vite/node_modules/rollup'; | ||
|
||
const packageJSON = JSON.parse(readFileSync(resolver(process.cwd(), './package.json')).toString()) | ||
const dependencies = [...Object.keys(packageJSON.dependencies), ...Object.keys(packageJSON.peerDependencies)] | ||
|
||
export type BuildFormat = 'iife' | 'es' | 'cjs' | 'esm-node' | ||
|
||
export const readDirRecursive = (path: string): string[] => { | ||
return readdirSync(path) | ||
.reduce<string[]>((acc, entry) => { | ||
const p = `${path}/${entry}` | ||
|
||
if (lstatSync(p).isDirectory()) { | ||
return [...acc, ...readDirRecursive(p)] | ||
} | ||
|
||
return [...acc, p] | ||
}, []) | ||
} | ||
|
||
export const resolve = { | ||
alias: { | ||
'@icons': resolver(process.cwd(), 'node_modules/@shopify/polaris-icons/dist/svg'), | ||
'@polaris': resolver(process.cwd(), './polaris/polaris-react/src'), | ||
'@': resolver(process.cwd(), './src'), | ||
'~': resolver(process.cwd(), './node_modules'), | ||
}, | ||
dedupe: ['vue'], | ||
} | ||
|
||
const rollupOutputOptions = (ext: string): RollupOptions['output'] => ({ | ||
entryFileNames: `[name].${ext}`, | ||
chunkFileNames: `[name].${ext}`, | ||
assetFileNames: '[name].[ext]', | ||
}) | ||
|
||
const rollupMjsBuildOptions: RollupOptions = { | ||
input: resolver(process.cwd(), 'src/polaris-vue.ts'), | ||
|
||
output: { | ||
sourcemap: true, | ||
dir: 'dist/esm-node', | ||
format: 'esm', | ||
...rollupOutputOptions('mjs'), | ||
}, | ||
} | ||
|
||
const libBuildOptions = (format: 'iife' | 'es' | 'cjs') => ({ | ||
entry: resolver(process.cwd(), 'src/polaris-vue.ts'), | ||
fileName: () => 'polaris-vue.js', | ||
formats: [format], | ||
|
||
// only for iife/umd | ||
name: 'PolarisVue', | ||
}) | ||
|
||
export default function createViteConfig (format: BuildFormat) { | ||
const isEsm = ['es', 'esm-node'].includes(format) | ||
const isNode = format === 'esm-node' | ||
|
||
const config = defineViteConfig({ | ||
resolve, | ||
|
||
css: { | ||
preprocessorOptions: { | ||
scss: { | ||
quietDeps: true, // Silent the deprecation warning | ||
}, | ||
}, | ||
modules: { | ||
generateScopedName, | ||
}, | ||
}, | ||
|
||
build: { | ||
outDir: `dist/${isEsm ? format : ''}`, | ||
cssCodeSplit: false, | ||
sourcemap: true, | ||
minify: isEsm ? false : 'esbuild', | ||
lib: libBuildOptions(isNode ? 'es' : format), | ||
}, | ||
|
||
plugins: [ | ||
vue({ | ||
isProduction: true, | ||
exclude: [/\.md$/, /\.spec\.ts$/, /\.spec\.disabled$/], | ||
}), | ||
svgLoader(), | ||
replaceCodePlugin({ | ||
replacements: [ | ||
{ | ||
from: '%POLARIS_VERSION%', | ||
to: packageJSON.polaris_version, | ||
}, | ||
], | ||
}), | ||
dts({ | ||
rollupTypes: true, | ||
outDir: 'dist/types', | ||
}), | ||
], | ||
}) | ||
|
||
// https://github.com/sanyuan0704/vite-plugin-chunk-split | ||
isEsm && config.plugins.push(chunkSplitPlugin({ strategy: 'unbundle' })) | ||
// isEsm && !isNode && config.plugins.push(appendComponentCss()) | ||
isEsm && config.plugins.push(removeSideEffectedChunks()) | ||
isEsm && config.plugins.push(fixVueGenericComponentFileNames) | ||
|
||
if (isNode) { | ||
config.build.rollupOptions = { | ||
external: [...dependencies, 'vue'], | ||
...rollupMjsBuildOptions, | ||
}; | ||
} else { | ||
config.build.rollupOptions = { | ||
external: [...dependencies, 'vue'], | ||
output: rollupOutputOptions('js'), | ||
} | ||
} | ||
|
||
return config | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
import type { Plugin } from 'vite' | ||
import { readdir, readFile, writeFile, lstat } from 'fs/promises' | ||
|
||
type Nothing = null | undefined | void | ||
type TransformFnResult = string | Nothing | ||
type TransformFn = (this: { outDir: string }, content: string, path: string) => TransformFnResult | Promise<TransformFnResult> | ||
|
||
export const createDistTransformPlugin = (options: { | ||
name: string, | ||
dir?: (outDir: string) => string, | ||
transform: TransformFn, | ||
}) => { | ||
let outDir = '' | ||
|
||
const processFiles = async (dir: string) => { | ||
return (await readdir(dir)) | ||
.map(async (entryName) => { | ||
const currentPath = `${dir}/${entryName}` | ||
|
||
if ((await lstat(currentPath)).isDirectory()) { | ||
return processFiles(currentPath) | ||
} | ||
|
||
const content = await readFile(currentPath, 'utf8') | ||
|
||
const result = await options.transform.call({ outDir }, content, currentPath) | ||
|
||
if (!result) { return } | ||
|
||
await writeFile(currentPath, result) | ||
}) | ||
} | ||
|
||
return (): Plugin => ({ | ||
name: 'vuestic:append-component-css', | ||
configResolved: (config) => { | ||
outDir = options.dir?.(config.build.outDir) || config.build.outDir | ||
}, | ||
closeBundle: async () => { | ||
processFiles(outDir) | ||
}, | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { Plugin } from 'vite'; | ||
|
||
const defineVitePlugin = <T extends Plugin>(p: T): Plugin & T => p; | ||
|
||
/** | ||
* When vue compiles file, it encode generic into file name | ||
* | ||
* @example | ||
* AppProvider.vue_vue_type_script_generic_Item%20extends%20Record%3Cstring%2C%20any%3E_setup_true_lang | ||
* | ||
* This might be helpful for compiler, but it makes file names unreadable and some bundlers may not allow encoded characters in file names. | ||
* This plugin replaces encoded characters in file names and source maps with underscores. | ||
*/ | ||
const GENERIC_NAME_REGEX = /.vue_vue_type_script_generic_.*_setup_true_lang/gm | ||
const URL_ENCODED_REGEX = /%([0-9]|[A-F]){2}/gm | ||
|
||
const replaceEncodedCharacters = (match: string) => match | ||
.replace(URL_ENCODED_REGEX, '_') // Replace any encoded character with underscore | ||
.replace(/_{2,}/g, '_') // Replace multiple underscores with single underscore | ||
|
||
export const fixVueGenericComponentFileNames = defineVitePlugin({ | ||
name: 'polaris-vue:fix-vue-generic-component-file-names', | ||
|
||
generateBundle (options, bundle) { | ||
Object.keys(bundle).forEach(fileName => { | ||
console.log(fileName); | ||
const file = bundle[fileName] | ||
|
||
// Replace encoded characters in generic names in source maps | ||
if (file.type === 'asset' && file.fileName.endsWith('.map')) { | ||
if (typeof file.source === 'string') { | ||
file.source = file.source | ||
.replace(GENERIC_NAME_REGEX, replaceEncodedCharacters) | ||
} | ||
} | ||
|
||
// Replace encoded characters in generic names in code | ||
if (file.type === 'chunk') { | ||
file.code = file.code | ||
.replace(GENERIC_NAME_REGEX, replaceEncodedCharacters) | ||
} | ||
|
||
// Update file name if it has encoded characters | ||
if (GENERIC_NAME_REGEX.test(fileName)) { | ||
const newFileName = replaceEncodedCharacters(fileName) | ||
|
||
bundle[newFileName] = { | ||
...bundle[fileName], | ||
fileName: newFileName, | ||
} | ||
|
||
delete bundle[fileName] | ||
} | ||
}) | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { createDistTransformPlugin } from './create-dist-transform'; | ||
|
||
/** | ||
* Vite think that some chunks contain side effects, | ||
* so it keep them in bundle and imports with `import "..."`. | ||
* It simply removes all imports from chunks that import side effected chunks | ||
* after build is done. | ||
*/ | ||
export const removeSideEffectedChunks = createDistTransformPlugin({ | ||
name: 'polaris-vue:remove-side-effected-chunks', | ||
|
||
transform: (content) => { | ||
return content.replace(/import ".*";(\n)*/gm, '') | ||
}, | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { defineConfig } from 'vite' | ||
import createViteConfig from './common' | ||
|
||
export default () => { | ||
return defineConfig({ | ||
...createViteConfig('cjs'), | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import { defineConfig } from 'vite' | ||
import createViteConfig from './common' | ||
|
||
export default () => defineConfig({ | ||
...createViteConfig('es'), | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.