├── .changeset ├── README.md ├── config.json ├── red-geckos-reflect.md ├── six-penguins-accept.md └── young-lies-allow.md ├── .eslintignore ├── .eslintrc.js ├── .github ├── CONTRIBUTING.md ├── FUNDING.yml ├── workflows-source │ └── ci.yaml └── workflows │ ├── ci.yaml │ └── release.yaml ├── .gitignore ├── .husky ├── .gitignore └── pre-commit ├── .npmrc ├── .prettierrc.json ├── .vscode ├── launch.json └── settings.json ├── LICENSE ├── docs ├── .vitepress │ ├── .gitignore │ └── config.js ├── assets │ └── show-preview.svg ├── index.md ├── introduction.md ├── package.json └── public │ ├── android-chrome-192x192.png │ ├── android-chrome-512x512.png │ ├── apple-touch-icon-precomposed.png │ ├── apple-touch-icon.png │ ├── browserconfig.xml │ ├── favicon-16x16.png │ ├── favicon-32x32.png │ ├── favicon.ico │ ├── logo.png │ ├── logo.svg │ ├── mstile-144x144.png │ ├── mstile-150x150.png │ ├── mstile-310x150.png │ ├── mstile-310x310.png │ ├── mstile-70x70.png │ ├── safari-pinned-tab.svg │ └── site.webmanifest ├── example ├── babel.config.js ├── jest.config.js ├── jsconfig.json ├── package.json ├── postcss.config.js ├── preview.ts ├── src │ ├── Card.vue │ ├── Input.vue │ ├── RepoList.spec.js │ ├── RepoList.vue │ └── style.css └── vite.config.js ├── extension ├── .gitignore ├── .npmignore ├── .vscodeignore ├── CHANGELOG.md ├── LICENSE ├── icon.svg ├── logo.png ├── package.json ├── readme.md ├── scripts │ └── build.mjs ├── src │ ├── getWebviewContent.ts │ ├── global.d.ts │ └── index.ts └── tsconfig.json ├── jest.config.js ├── lint-staged.config.js ├── package.json ├── packages ├── preview-compiler │ ├── CHANGELOG.md │ ├── package.json │ ├── src │ │ └── index.ts │ └── tsconfig.json ├── preview-provider │ ├── .npmignore │ ├── CHANGELOG.md │ ├── package.json │ ├── src │ │ ├── activeComponent.ts │ │ ├── communication.ts │ │ ├── components.ts │ │ ├── fetch.ts │ │ ├── index.ts │ │ └── utilities.ts │ └── tsconfig.json ├── preview-shell │ ├── CHANGELOG.md │ ├── index.html │ ├── package.json │ ├── postcss.config.js │ ├── public │ │ ├── browserconfig.xml │ │ ├── favicon.ico │ │ ├── icons │ │ │ ├── android-icon-144x144.png │ │ │ ├── android-icon-192x192.png │ │ │ ├── android-icon-36x36.png │ │ │ ├── android-icon-48x48.png │ │ │ ├── android-icon-72x72.png │ │ │ ├── android-icon-96x96.png │ │ │ ├── apple-icon-114x114.png │ │ │ ├── apple-icon-120x120.png │ │ │ ├── apple-icon-144x144.png │ │ │ ├── apple-icon-152x152.png │ │ │ ├── apple-icon-180x180.png │ │ │ ├── apple-icon-57x57.png │ │ │ ├── apple-icon-60x60.png │ │ │ ├── apple-icon-72x72.png │ │ │ ├── apple-icon-76x76.png │ │ │ ├── apple-icon-precomposed.png │ │ │ ├── apple-icon.png │ │ │ ├── favicon-16x16.png │ │ │ ├── favicon-32x32.png │ │ │ ├── favicon-96x96.png │ │ │ ├── ms-icon-144x144.png │ │ │ ├── ms-icon-150x150.png │ │ │ ├── ms-icon-310x310.png │ │ │ └── ms-icon-70x70.png │ │ └── manifest.json │ ├── src │ │ ├── Root.vue │ │ ├── app.css │ │ ├── app.ts │ │ ├── assets │ │ │ ├── MacBook-Pro-16.png │ │ │ ├── assets.d.ts │ │ │ ├── device-freeform.svg │ │ │ ├── iPad-Pro-13-Landscape.png │ │ │ ├── iPad-Pro-13-Landscape.svg │ │ │ ├── iPad-Pro-13-Portrait.png │ │ │ ├── iPad-Pro-13-Portrait.svg │ │ │ ├── iPhone-11-Landscape.png │ │ │ ├── iPhone-11-Landscape.svg │ │ │ ├── iPhone-11-Portrait.png │ │ │ └── iPhone-11-Portrait.svg │ │ ├── components.ts │ │ ├── components │ │ │ ├── BaseDevice.vue │ │ │ ├── Browser.vue │ │ │ ├── ConfiguredDevice.vue │ │ │ ├── Content.vue │ │ │ ├── Device.vue │ │ │ ├── DeviceSelector.vue │ │ │ ├── Example.vue │ │ │ ├── ExplorerComponents.vue │ │ │ ├── FreeformDevice.vue │ │ │ ├── Viewport.vue │ │ │ ├── ZoomSelector.vue │ │ │ └── device-frame-hack.vue │ │ ├── config.ts │ │ ├── devices │ │ │ └── index.ts │ │ ├── index.ts │ │ ├── pages │ │ │ ├── dashboard.vue │ │ │ └── sandbox.vue │ │ ├── router.ts │ │ └── utilities.ts │ ├── tailwind.config.js │ ├── tsconfig.json │ └── vite.config.js ├── preview-test-utils │ ├── .npmignore │ ├── CHANGELOG.md │ ├── jest.config.js │ ├── package.json │ ├── placeholder.js │ ├── src │ │ ├── index.ts │ │ ├── stacktrace.ts │ │ ├── transform.ts │ │ └── vm.ts │ ├── test │ │ ├── fixtures │ │ │ ├── Example.vue │ │ │ ├── MockComponent.vue │ │ │ ├── MockFetchRequest.vue │ │ │ └── api │ │ │ │ └── foo.json │ │ ├── setup.ts │ │ ├── tsconfig.json │ │ └── usePreview.spec.ts │ └── tsconfig.json └── preview │ ├── CHANGELOG.md │ ├── bin │ └── preview.js │ ├── package.json │ ├── src │ ├── cli.ts │ ├── generators.ts │ ├── index.ts │ ├── send.ts │ ├── store │ │ ├── ComponentMetadataStore.ts │ │ ├── DescriptorStore.ts │ │ ├── FileSystemHost.ts │ │ └── PreviewCompilerStore.ts │ ├── utils.ts │ └── virtual-resource.ts │ └── tsconfig.json ├── pnpm-lock.yaml ├── pnpm-workspace.yaml ├── readme.md ├── rollup.config.js ├── scripts └── prepare-workflows.mjs └── tsconfig.base.json /.changeset/README.md: -------------------------------------------------------------------------------- 1 | # Changesets 2 | 3 | Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works 4 | with multi-package repos, or single-package repos to help you version and publish your code. You can 5 | find the full documentation for it [in our repository](https://github.com/changesets/changesets) 6 | 7 | We have a quick list of common questions to get you started engaging with this project in 8 | [our documentation](https://github.com/changesets/changesets/blob/master/docs/common-questions.md) 9 | -------------------------------------------------------------------------------- /.changeset/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://unpkg.com/@changesets/config@1.4.0/schema.json", 3 | "changelog": "@changesets/cli/changelog", 4 | "commit": false, 5 | "linked": [], 6 | "access": "public", 7 | "baseBranch": "main", 8 | "updateInternalDependencies": "patch" 9 | } 10 | -------------------------------------------------------------------------------- /.changeset/red-geckos-reflect.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@vuedx/preview-provider': patch 3 | --- 4 | 5 | fetch stub for delayed response 6 | 7 | - `$p.http.delayed()` 8 | -------------------------------------------------------------------------------- /.changeset/six-penguins-accept.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@vuedx/preview-shell': patch 3 | --- 4 | 5 | Global overrides for device and zoom 6 | -------------------------------------------------------------------------------- /.changeset/young-lies-allow.md: -------------------------------------------------------------------------------- 1 | --- 2 | '@vuedx/preview-shell': patch 3 | --- 4 | 5 | Filter components 6 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | packages/example 2 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | extends: '@vuedx/eslint-config', 4 | }; 5 | -------------------------------------------------------------------------------- /.github/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | > This document is WIP. If you have any questions, please create an issue. 4 | 5 | ## Development 6 | 7 | ```bash 8 | # install dependencies 9 | pnpm install 10 | # start rollup dev build watcher 11 | pnpm run watch 12 | # start preview in `packages/example` directory 13 | pnpm start 14 | ``` 15 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: znck 2 | -------------------------------------------------------------------------------- /.github/workflows-source/ci.yaml: -------------------------------------------------------------------------------- 1 | name: CI/CD 2 | 3 | on: 4 | pull_request: 5 | branches: 6 | - main 7 | push: 8 | branches: 9 | - main 10 | 11 | .checkout: &checkout 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | 15 | .node_modules_cache: &node_modules_cache 16 | - name: Cache node packages 17 | uses: actions/cache@v2 18 | env: 19 | cache-name: pnpm-modules 20 | with: 21 | key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('**/pnpm-lock.yaml') }} 22 | restore-keys: | 23 | ${{ runner.os }}-build-${{ env.cache-name }}- 24 | ${{ runner.os }}-build- 25 | ${{ runner.os }}- 26 | path: | 27 | ~/.pnpm-store 28 | ${{ github.workspace }}/.pnpm 29 | .node: &node 30 | - name: Setup Node 31 | uses: actions/setup-node@v2 32 | with: 33 | node-version: '16' 34 | 35 | .pnpm: &pnpm 36 | - name: Setup PNPM 37 | uses: pnpm/action-setup@v2.0.1 38 | with: 39 | version: '6.2.5' 40 | run_install: | 41 | - recursive: true 42 | args: [--frozen-lockfile] 43 | 44 | .setup: &setup 45 | - *checkout 46 | - *node_modules_cache 47 | - *node 48 | - *pnpm 49 | 50 | .download: &download 51 | - name: Download build artefact 52 | uses: actions/download-artifact@v2 53 | with: 54 | name: build-artefact 55 | path: '.' 56 | 57 | concurrency: 58 | group: build-${{ github.ref }} 59 | cancel-in-progress: ${{ !startsWith(github.event.head_commit.message, 'release:') }} 60 | 61 | jobs: 62 | build: 63 | name: Build 64 | runs-on: ubuntu-latest 65 | if: "!startsWith(github.event.head_commit.message, 'skip ci')" 66 | steps: 67 | - *setup 68 | - name: Build 69 | run: pnpm recursive run build 70 | - name: Upload build artefact 71 | uses: actions/upload-artifact@v2 72 | with: 73 | name: build-artefact 74 | retention-days: 30 75 | path: | 76 | ./packages/*/dist 77 | ./extension/dist 78 | 79 | unit: 80 | needs: build 81 | strategy: 82 | matrix: 83 | os: [ubuntu-latest] 84 | node_version: ['14', '16'] 85 | include: 86 | - os: ubuntu-latest 87 | node: '16' 88 | command: 'coverage' 89 | runs-on: ${{ matrix.os }} 90 | name: Node ${{ matrix.node_version }} on ${{ matrix.os }} 91 | continue-on-error: ${{ startsWith(github.event.head_commit.message, 'release:') }} 92 | steps: 93 | - *checkout 94 | - *node_modules_cache 95 | - name: Setup Node 96 | uses: actions/setup-node@v2 97 | with: 98 | node-version: ${{ matrix.node_version }} 99 | - *pnpm 100 | - *download 101 | - name: Test 102 | run: pnpm test 103 | - name: Collect coverage 104 | if: matrix.command == 'coverage' 105 | uses: codecov/codecov-action@v1 106 | with: 107 | file: ./coverage/coverage-final.json 108 | 109 | pre-release: 110 | name: Pre-release 111 | runs-on: ubuntu-latest 112 | needs: unit 113 | concurrency: 114 | group: pre-release 115 | cancel-in-progress: true 116 | steps: 117 | - *setup 118 | - *download 119 | - name: Publish Pre-release Extension 120 | run: | 121 | pnpm recursive --filter ./extension run build 122 | pnpm recursive --filter ./extension run pre-release 123 | env: 124 | RELEASE_CHANNEL: pre-release 125 | VSCODE_MARKETPLACE_TOKEN: ${{ secrets.VSCODE_MARKETPLACE_TOKEN }} 126 | - name: Publish Pre-release Packages 127 | run: | 128 | pnpm recursive --filter ./packages exec -- pnpm version prerelease --no-commit-hooks --no-git-tag-version --preid=next-$(date +%s) 129 | echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc 130 | pnpm recursive --filter ./packages publish --tag next --access public --no-git-checks 131 | env: 132 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 133 | 134 | check_release: 135 | name: Check Release 136 | runs-on: ubuntu-latest 137 | needs: unit 138 | if: startsWith(github.event.head_commit.message, 'release:') 139 | steps: 140 | - run: echo 'ok' 141 | 142 | release: 143 | name: Release 144 | runs-on: ubuntu-latest 145 | environment: 146 | name: Production 147 | url: https://marketplace.visualstudio.com/items?itemName=znck.preview 148 | needs: check_release 149 | concurrency: 150 | group: release 151 | cancel-in-progress: false 152 | steps: 153 | - *setup 154 | - *download 155 | - name: Publish Packages 156 | run: | 157 | echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc 158 | pnpm recursive publish --no-git-checks 159 | env: 160 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 161 | - name: Publish Extension 162 | run: | 163 | pnpm recursive --filter ./extension run build 164 | pnpm recursive --filter ./extension run release 165 | pnpm -y osvx publish -p ${OVSX_REGISTRY_TOKEN} ./extension/preview.vsix 166 | env: 167 | VSCODE_MARKETPLACE_TOKEN: ${{ secrets.VSCODE_MARKETPLACE_TOKEN }} 168 | OVSX_REGISTRY_TOKEN: ${{ secrets.OVSX_REGISTRY_TOKEN }} 169 | continue-on-error: true 170 | - uses: 'marvinpinto/action-automatic-releases@latest' 171 | with: 172 | repo_token: '${{ secrets.GITHUB_TOKEN }}' 173 | automatic_release_tag: 'latest' 174 | prerelease: false 175 | files: | 176 | extension/CHANGELOG.md 177 | extension/preview.vsix 178 | packages/*/CHANGELOG.md 179 | -------------------------------------------------------------------------------- /.github/workflows/ci.yaml: -------------------------------------------------------------------------------- 1 | # THIS FILE WAS AUTOMATICALLY GENERATED (DO NOT MODIFY) from ../workflows-source/ci.yaml 2 | name: CI/CD 3 | 'on': 4 | pull_request: 5 | branches: 6 | - main 7 | push: 8 | branches: 9 | - main 10 | concurrency: 11 | group: build-${{ github.ref }} 12 | cancel-in-progress: ${{ !startsWith(github.event.head_commit.message, 'release:') }} 13 | jobs: 14 | build: 15 | name: Build 16 | runs-on: ubuntu-latest 17 | if: "!startsWith(github.event.head_commit.message, 'skip ci')" 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@v2 21 | - name: Cache node packages 22 | uses: actions/cache@v2 23 | env: 24 | cache-name: pnpm-modules 25 | with: 26 | key: >- 27 | ${{ runner.os }}-build-${{ env.cache-name }}-${{ 28 | hashFiles('**/pnpm-lock.yaml') }} 29 | restore-keys: | 30 | ${{ runner.os }}-build-${{ env.cache-name }}- 31 | ${{ runner.os }}-build- 32 | ${{ runner.os }}- 33 | path: | 34 | ~/.pnpm-store 35 | ${{ github.workspace }}/.pnpm 36 | - name: Setup Node 37 | uses: actions/setup-node@v2 38 | with: 39 | node-version: '16' 40 | - name: Setup PNPM 41 | uses: pnpm/action-setup@v2.0.1 42 | with: 43 | version: 6.2.5 44 | run_install: | 45 | - recursive: true 46 | args: [--frozen-lockfile] 47 | - name: Build 48 | run: pnpm recursive run build 49 | - name: Upload build artefact 50 | uses: actions/upload-artifact@v2 51 | with: 52 | name: build-artefact 53 | retention-days: 30 54 | path: | 55 | ./packages/*/dist 56 | ./extension/dist 57 | unit: 58 | needs: build 59 | strategy: 60 | matrix: 61 | os: 62 | - ubuntu-latest 63 | node_version: 64 | - '14' 65 | - '16' 66 | include: 67 | - os: ubuntu-latest 68 | node: '16' 69 | command: coverage 70 | runs-on: ${{ matrix.os }} 71 | name: Node ${{ matrix.node_version }} on ${{ matrix.os }} 72 | continue-on-error: ${{ startsWith(github.event.head_commit.message, 'release:') }} 73 | steps: 74 | - name: Checkout 75 | uses: actions/checkout@v2 76 | - name: Cache node packages 77 | uses: actions/cache@v2 78 | env: 79 | cache-name: pnpm-modules 80 | with: 81 | key: >- 82 | ${{ runner.os }}-build-${{ env.cache-name }}-${{ 83 | hashFiles('**/pnpm-lock.yaml') }} 84 | restore-keys: | 85 | ${{ runner.os }}-build-${{ env.cache-name }}- 86 | ${{ runner.os }}-build- 87 | ${{ runner.os }}- 88 | path: | 89 | ~/.pnpm-store 90 | ${{ github.workspace }}/.pnpm 91 | - name: Setup Node 92 | uses: actions/setup-node@v2 93 | with: 94 | node-version: ${{ matrix.node_version }} 95 | - name: Setup PNPM 96 | uses: pnpm/action-setup@v2.0.1 97 | with: 98 | version: 6.2.5 99 | run_install: | 100 | - recursive: true 101 | args: [--frozen-lockfile] 102 | - name: Download build artefact 103 | uses: actions/download-artifact@v2 104 | with: 105 | name: build-artefact 106 | path: . 107 | - name: Test 108 | run: pnpm test 109 | - name: Collect coverage 110 | if: matrix.command == 'coverage' 111 | uses: codecov/codecov-action@v1 112 | with: 113 | file: ./coverage/coverage-final.json 114 | pre-release: 115 | name: Pre-release 116 | runs-on: ubuntu-latest 117 | needs: unit 118 | concurrency: 119 | group: pre-release 120 | cancel-in-progress: true 121 | steps: 122 | - name: Checkout 123 | uses: actions/checkout@v2 124 | - name: Cache node packages 125 | uses: actions/cache@v2 126 | env: 127 | cache-name: pnpm-modules 128 | with: 129 | key: >- 130 | ${{ runner.os }}-build-${{ env.cache-name }}-${{ 131 | hashFiles('**/pnpm-lock.yaml') }} 132 | restore-keys: | 133 | ${{ runner.os }}-build-${{ env.cache-name }}- 134 | ${{ runner.os }}-build- 135 | ${{ runner.os }}- 136 | path: | 137 | ~/.pnpm-store 138 | ${{ github.workspace }}/.pnpm 139 | - name: Setup Node 140 | uses: actions/setup-node@v2 141 | with: 142 | node-version: '16' 143 | - name: Setup PNPM 144 | uses: pnpm/action-setup@v2.0.1 145 | with: 146 | version: 6.2.5 147 | run_install: | 148 | - recursive: true 149 | args: [--frozen-lockfile] 150 | - name: Download build artefact 151 | uses: actions/download-artifact@v2 152 | with: 153 | name: build-artefact 154 | path: . 155 | - name: Publish Pre-release Extension 156 | run: | 157 | pnpm recursive --filter ./extension run build 158 | pnpm recursive --filter ./extension run pre-release 159 | env: 160 | RELEASE_CHANNEL: pre-release 161 | VSCODE_MARKETPLACE_TOKEN: ${{ secrets.VSCODE_MARKETPLACE_TOKEN }} 162 | - name: Publish Pre-release Packages 163 | run: > 164 | pnpm recursive --filter ./packages exec -- pnpm version prerelease 165 | --no-commit-hooks --no-git-tag-version --preid=next-$(date +%s) 166 | 167 | echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc 168 | 169 | pnpm recursive --filter ./packages publish --tag next --access public 170 | --no-git-checks 171 | env: 172 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 173 | check_release: 174 | name: Check Release 175 | runs-on: ubuntu-latest 176 | needs: unit 177 | if: startsWith(github.event.head_commit.message, 'release:') 178 | steps: 179 | - run: echo 'ok' 180 | release: 181 | name: Release 182 | runs-on: ubuntu-latest 183 | environment: 184 | name: Production 185 | url: https://marketplace.visualstudio.com/items?itemName=znck.preview 186 | needs: check_release 187 | concurrency: 188 | group: release 189 | cancel-in-progress: false 190 | steps: 191 | - name: Checkout 192 | uses: actions/checkout@v2 193 | - name: Cache node packages 194 | uses: actions/cache@v2 195 | env: 196 | cache-name: pnpm-modules 197 | with: 198 | key: >- 199 | ${{ runner.os }}-build-${{ env.cache-name }}-${{ 200 | hashFiles('**/pnpm-lock.yaml') }} 201 | restore-keys: | 202 | ${{ runner.os }}-build-${{ env.cache-name }}- 203 | ${{ runner.os }}-build- 204 | ${{ runner.os }}- 205 | path: | 206 | ~/.pnpm-store 207 | ${{ github.workspace }}/.pnpm 208 | - name: Setup Node 209 | uses: actions/setup-node@v2 210 | with: 211 | node-version: '16' 212 | - name: Setup PNPM 213 | uses: pnpm/action-setup@v2.0.1 214 | with: 215 | version: 6.2.5 216 | run_install: | 217 | - recursive: true 218 | args: [--frozen-lockfile] 219 | - name: Download build artefact 220 | uses: actions/download-artifact@v2 221 | with: 222 | name: build-artefact 223 | path: . 224 | - name: Publish Packages 225 | run: | 226 | echo '//registry.npmjs.org/:_authToken=${NPM_TOKEN}' > .npmrc 227 | pnpm recursive publish --no-git-checks 228 | env: 229 | NPM_TOKEN: ${{ secrets.NPM_TOKEN }} 230 | - name: Publish Extension 231 | run: > 232 | pnpm recursive --filter ./extension run build 233 | 234 | pnpm recursive --filter ./extension run release 235 | 236 | pnpm -y osvx publish -p ${OVSX_REGISTRY_TOKEN} 237 | ./extension/preview.vsix 238 | env: 239 | VSCODE_MARKETPLACE_TOKEN: ${{ secrets.VSCODE_MARKETPLACE_TOKEN }} 240 | OVSX_REGISTRY_TOKEN: ${{ secrets.OVSX_REGISTRY_TOKEN }} 241 | continue-on-error: true 242 | - uses: marvinpinto/action-automatic-releases@latest 243 | with: 244 | repo_token: ${{ secrets.GITHUB_TOKEN }} 245 | automatic_release_tag: latest 246 | prerelease: false 247 | files: | 248 | extension/CHANGELOG.md 249 | extension/preview.vsix 250 | packages/*/CHANGELOG.md 251 | -------------------------------------------------------------------------------- /.github/workflows/release.yaml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | jobs: 8 | create: 9 | name: Create release PR 10 | runs-on: ubuntu-latest 11 | steps: 12 | - name: Checkout 13 | uses: actions/checkout@v2 14 | with: 15 | fetch-depth: 0 16 | 17 | - name: Cache node packages 18 | uses: actions/cache@v2 19 | env: 20 | cache-name: pnpm-modules 21 | with: 22 | key: >- 23 | ${{ runner.os }}-build-${{ env.cache-name }}-${{ 24 | hashFiles('**/pnpm-lock.yaml') }} 25 | restore-keys: | 26 | ${{ runner.os }}-build-${{ env.cache-name }}- 27 | ${{ runner.os }}-build- 28 | ${{ runner.os }}- 29 | path: | 30 | ~/.pnpm-store 31 | ${{ github.workspace }}/.pnpm 32 | - name: Setup Node 33 | uses: actions/setup-node@v2 34 | with: 35 | node-version: '16' 36 | - name: Setup PNPM 37 | uses: pnpm/action-setup@v2.0.1 38 | with: 39 | version: 6.2.5 40 | run_install: | 41 | - recursive: true 42 | args: [--frozen-lockfile] 43 | 44 | - name: Create Release Pull Request 45 | uses: changesets/action@master 46 | with: 47 | title: 'release: new versions' 48 | commit: 'release: new versions' 49 | env: 50 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 51 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | .eslintcache 4 | dist 5 | coverage 6 | _ 7 | .pnpm/ 8 | -------------------------------------------------------------------------------- /.husky/.gitignore: -------------------------------------------------------------------------------- 1 | _ 2 | -------------------------------------------------------------------------------- /.husky/pre-commit: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | . "$(dirname "$0")/_/husky.sh" 3 | 4 | $(pnpm bin)/lint-staged 5 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | scope=@vuedx 2 | engine-strict = true 3 | virtual-store-dir = .pnpm 4 | -------------------------------------------------------------------------------- /.prettierrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "singleQuote": true, 4 | "trailingComma": "es5", 5 | "printWidth": 100 6 | } 7 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | // Use IntelliSense to learn about possible attributes. 3 | // Hover to view descriptions of existing attributes. 4 | // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 5 | "version": "0.2.0", 6 | "configurations": [ 7 | { 8 | "name": "Extension: VS Code", 9 | "type": "extensionHost", 10 | "request": "launch", 11 | "runtimeExecutable": "${execPath}", 12 | "env": { 13 | "TSS_DEBUG": "9999" 14 | }, 15 | "args": [ 16 | "--extensionDevelopmentPath=${workspaceRoot}/extension", 17 | "${workspaceRoot}/example" 18 | ], 19 | "outFiles": ["${workspaceRoot}/extension/dist/*.js"] 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cSpell.words": [ 3 | "codecov", 4 | "sirv" 5 | ] 6 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Rahul Kadyan 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 | -------------------------------------------------------------------------------- /docs/.vitepress/.gitignore: -------------------------------------------------------------------------------- 1 | .cache/ 2 | .temp/ 3 | -------------------------------------------------------------------------------- /docs/.vitepress/config.js: -------------------------------------------------------------------------------- 1 | // @ts-check 2 | module.exports = /** @type {import('vitepress').UserConfig} */ ({ 3 | title: 'Preview', 4 | description: '', 5 | head: [ 6 | ['link', { rel: 'apple-touch-icon', sizes: '180x180', href: '/apple-touch-icon.png' }], 7 | ['link', { rel: 'icon', type: 'image/png', sizes: '32x32', href: '/favicon-32x32.png' }], 8 | ['link', { rel: 'icon', type: 'image/png', sizes: '16x16', href: '/favicon-16x16.png' }], 9 | ['link', { rel: 'manifest', href: '/site.webmanifest' }], 10 | ['link', { rel: 'mask-icon', href: '/safari-pinned-tab.svg', color: '#ec3d3d' }], 11 | ['meta', { name: 'apple-mobile-web-app-title', content: 'VueDX Preview' }], 12 | ['meta', { name: 'application-name', content: 'VueDX Preview' }], 13 | ['meta', { name: 'msapplication-TileColor', content: '#b91d47' }], 14 | ['meta', { name: 'theme-color', content: '#ffffff' }], 15 | ], 16 | themeConfig: { 17 | locales: {}, 18 | }, 19 | }); 20 | -------------------------------------------------------------------------------- /docs/assets/show-preview.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /docs/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | home: true 3 | title: Preview | VueDX 4 | heroImage: /logo.png 5 | actionText: Get Started 6 | actionLink: /introduction.html 7 | features: 8 | - title: Sandbox 9 | details: Build components in isolated environment. 10 | - title: Visibility 11 | details: Render components in any states. 12 | - title: 13 | details: 14 | footer: MIT Licensed | Copyright © 2021-present Rahul Kadyan 15 | --- 16 | -------------------------------------------------------------------------------- /docs/introduction.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/introduction.md -------------------------------------------------------------------------------- /docs/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "-docs", 4 | "scripts": { 5 | "dev": "vitepress" 6 | }, 7 | "devDependencies": { 8 | "vitepress": "^0.16.1" 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /docs/public/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/android-chrome-192x192.png -------------------------------------------------------------------------------- /docs/public/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/android-chrome-512x512.png -------------------------------------------------------------------------------- /docs/public/apple-touch-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/apple-touch-icon-precomposed.png -------------------------------------------------------------------------------- /docs/public/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/apple-touch-icon.png -------------------------------------------------------------------------------- /docs/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | #b91d47 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /docs/public/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/favicon-16x16.png -------------------------------------------------------------------------------- /docs/public/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/favicon-32x32.png -------------------------------------------------------------------------------- /docs/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/favicon.ico -------------------------------------------------------------------------------- /docs/public/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/logo.png -------------------------------------------------------------------------------- /docs/public/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /docs/public/mstile-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/mstile-144x144.png -------------------------------------------------------------------------------- /docs/public/mstile-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/mstile-150x150.png -------------------------------------------------------------------------------- /docs/public/mstile-310x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/mstile-310x150.png -------------------------------------------------------------------------------- /docs/public/mstile-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/mstile-310x310.png -------------------------------------------------------------------------------- /docs/public/mstile-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/docs/public/mstile-70x70.png -------------------------------------------------------------------------------- /docs/public/safari-pinned-tab.svg: -------------------------------------------------------------------------------- 1 | 2 | 4 | 7 | 8 | Created by potrace 1.14, written by Peter Selinger 2001-2017 9 | 10 | 12 | 17 | 21 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /docs/public/site.webmanifest: -------------------------------------------------------------------------------- 1 | { 2 | "name": "VueDX Preview", 3 | "short_name": "VueDX Preview", 4 | "icons": [ 5 | { 6 | "src": "/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "theme_color": "#ffffff", 17 | "background_color": "#ffffff" 18 | } 19 | -------------------------------------------------------------------------------- /example/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | [ 4 | '@babel/preset-env', 5 | { 6 | targets: { 7 | node: 'current', 8 | }, 9 | }, 10 | ], 11 | ], 12 | }; 13 | -------------------------------------------------------------------------------- /example/jest.config.js: -------------------------------------------------------------------------------- 1 | const { name } = require('./package.json'); 2 | 3 | /** @type {import('@jest/types').Config.InitialOptions} */ 4 | module.exports = { 5 | displayName: { 6 | name, 7 | color: 'magenta', 8 | }, 9 | verbose: true, 10 | moduleFileExtensions: ['js', 'json', 'vue'], 11 | transform: { 12 | '^.+\\.js$': 'babel-jest', 13 | '^.+\\.vue$': 'vue-jest', 14 | }, 15 | transformIgnorePatterns: ['node_modules'], 16 | rootDir: __dirname, 17 | }; 18 | -------------------------------------------------------------------------------- /example/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "include": ["src"], 4 | "compilerOptions": { "lib": ["ES2019", "DOM"], "checkJs": true } 5 | } 6 | -------------------------------------------------------------------------------- /example/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "example", 4 | "version": "0.0.0", 5 | "buildConfig": { 6 | "useMain": false 7 | }, 8 | "scripts": { 9 | "start": "node ../preview/bin/preview.js", 10 | "dev": "vite", 11 | "test": "jest" 12 | }, 13 | "dependencies": { 14 | "vue": "^3.0.5" 15 | }, 16 | "devDependencies": { 17 | "@babel/core": "^7.12.10", 18 | "@babel/preset-env": "^7.12.11", 19 | "@testing-library/dom": "^7.29.4", 20 | "@types/jest": "^26.0.20", 21 | "@vitejs/plugin-vue": "^1.1.1", 22 | "@vue/compiler-sfc": "^3.0.5", 23 | "@vue/test-utils": "2.0.0-beta.14", 24 | "@vuedx/preview-test-utils": "link:../packages/preview-test-utils", 25 | "babel-jest": "^26.6.3", 26 | "jest": "^26.6.3", 27 | "tailwindcss": "~2.0.2", 28 | "typescript": "^4.1.3", 29 | "vite": "^2.3.6", 30 | "vue-jest": "5.0.0-alpha.8", 31 | "whatwg-fetch": "^3.5.0" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /example/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { plugins: [] }; 2 | -------------------------------------------------------------------------------- /example/preview.ts: -------------------------------------------------------------------------------- 1 | import './src/style.css'; 2 | 3 | -------------------------------------------------------------------------------- /example/src/Card.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /example/src/Input.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 101 | -------------------------------------------------------------------------------- /example/src/RepoList.spec.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable no-undef */ 2 | import { waitFor } from '@testing-library/dom'; 3 | import { mount } from '@vue/test-utils'; 4 | import { usePreview } from '@vuedx/preview-test-utils'; 5 | import 'whatwg-fetch'; 6 | 7 | describe('RepoList', () => { 8 | test('should render list of repositories', async () => { 9 | const wrapper = mount(usePreview('one repo')); 10 | await waitFor(() => { 11 | expect(wrapper.findAll('li')).toHaveLength(1); 12 | expect(wrapper.find('li').text()).toBe('preview'); 13 | }); 14 | }); 15 | }); 16 | -------------------------------------------------------------------------------- /example/src/RepoList.vue: -------------------------------------------------------------------------------- 1 | 18 | 19 | 26 | 27 | 28 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /example/src/style.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | 3 | @tailwind components; 4 | 5 | @tailwind utilities; 6 | -------------------------------------------------------------------------------- /example/vite.config.js: -------------------------------------------------------------------------------- 1 | const vuePlugin = require('@vitejs/plugin-vue').default; 2 | const { PreviewPlugin } = require('../packages/preview'); 3 | 4 | module.exports = /** @type {import('vite').UserConfig} */ ({ 5 | plugins: [vuePlugin(), PreviewPlugin()], 6 | clearScreen: false, 7 | server: { 8 | host: 'dev.thesemetrics.org', 9 | port: 2000, 10 | }, 11 | }); 12 | -------------------------------------------------------------------------------- /extension/.gitignore: -------------------------------------------------------------------------------- 1 | package.bak.json 2 | *.vsix 3 | -------------------------------------------------------------------------------- /extension/.npmignore: -------------------------------------------------------------------------------- 1 | /scripts 2 | -------------------------------------------------------------------------------- /extension/.vscodeignore: -------------------------------------------------------------------------------- 1 | ** 2 | !readme.md 3 | !logo.png 4 | !LICENSE 5 | !dist/ 6 | -------------------------------------------------------------------------------- /extension/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # preview 2 | 3 | ## 0.4.0 4 | 5 | ### Minor Changes 6 | 7 | - ff930e3: Use `/__preview` path prefix for plugin mode 8 | 9 | BREAKING CHANGE: Internal virtual files also use `__preview` prefix, instead of `@preview`. 10 | 11 | ## 0.3.2 12 | 13 | ### Patch Changes 14 | 15 | - cc16fc4: Ignore failures in metadata extraction from static code analysis 16 | 17 | ## 0.3.1 18 | 19 | ### Patch Changes 20 | 21 | - dd448e6: Sync color-scheme with VS Code 22 | 23 | ## 0.3.0 24 | 25 | ### Minor Changes 26 | 27 | - b0eea6a: New commands 28 | 29 | - `preview.showSource` — Open source .vue file from preview panel 30 | - `preview.update` — Update `@vuedx/preview` package 31 | - `preview.refresh` - Refresh preview panel 32 | 33 | - b0eea6a: Move "open preview in browser" to `editor/title/context` menu 34 | 35 | ### Patch Changes 36 | 37 | - b0eea6a: Build using @vuedx/monorepo-tools 38 | 39 | ## 0.2.4 40 | 41 | ### Patch Changes 42 | 43 | - 83e89e5: Use consistent virtual resource scheme 44 | 45 | - Use `@preview:component/${type}.${ext}` for component scoped resources 46 | - Use `@preview:shell/` for proxying pre-built shell application 47 | - Use `@preview:components.js` for component index 48 | - Use `@preview:user/setup.js` for custom runtime setup file 49 | 50 | ## 0.2.1 51 | 52 | ### Patch Changes 53 | 54 | - 1b39181: Bump all versions to test continuous release CI 55 | 56 | ## 0.2.0 57 | 58 | ### Minor Changes 59 | 60 | - 387878f: Open preview in browser 61 | 62 | - Add command to open preview in browser: `preview.open` 63 | - Add editor title menu entry for `preview.open` 64 | 65 | ## 0.1.5 66 | 67 | ### Patch Changes 68 | 69 | - 18a1b02: Bump version 70 | 71 | ## 0.1.4 72 | 73 | ### Patch Changes 74 | 75 | - e3ba132: Update HMR API 76 | 77 | - Version lock on vite@2.0.0-beta.44 78 | - Remove forked HMR client and use `/@vite/client` instead 79 | 80 | ## 0.1.3 81 | 82 | ### Patch Changes 83 | 84 | - 03225aa: Update vite HMR API 85 | 86 | ## 0.1.2 87 | 88 | ### Patch Changes 89 | 90 | - c6ed393: Automated release workflow 91 | 92 | ## 0.1.1 93 | 94 | ### Patch Changes 95 | 96 | - c2d20eb: Setup CI release workflow 97 | 98 | ## 0.1.0 99 | 100 | ### Minor Changes 101 | 102 | - d34a262: VS Code preview extension 103 | -------------------------------------------------------------------------------- /extension/LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Rahul Kadyan 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 | -------------------------------------------------------------------------------- /extension/icon.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /extension/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/extension/logo.png -------------------------------------------------------------------------------- /extension/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "version": "0.4.1", 4 | "name": "preview", 5 | "publisher": "znck", 6 | "displayName": "Preview", 7 | "description": "A storyboarding and prototyping tool for Vue.", 8 | "main": "dist/extension.js", 9 | "icon": "logo.png", 10 | "buildConfig": { 11 | "useMain": false, 12 | "sources": { 13 | "src/index.ts": [ 14 | { 15 | "format": "commonjs", 16 | "file": "dist/extension.js", 17 | "bundle": { 18 | "external": [ 19 | "vscode" 20 | ] 21 | } 22 | } 23 | ] 24 | }, 25 | "external": [ 26 | "vscode" 27 | ] 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "https://github.com/znck/preview.git", 32 | "directory": "extension" 33 | }, 34 | "files": [ 35 | "dist", 36 | "logo.png" 37 | ], 38 | "activationEvents": [ 39 | "onCommand:preview.show", 40 | "onCommand:preview.open", 41 | "onCommand:preview.stop", 42 | "onLanguage:vue" 43 | ], 44 | "contributes": { 45 | "commands": [ 46 | { 47 | "command": "preview.show", 48 | "enablement": "resourceLangId == vue", 49 | "title": "Show preview", 50 | "category": "Preview", 51 | "icon": "$(open-preview)" 52 | }, 53 | { 54 | "command": "preview.showSource", 55 | "enablement": "preview:isFocused", 56 | "title": "Show .vue file", 57 | "category": "Preview", 58 | "icon": "$(go-to-file)" 59 | }, 60 | { 61 | "command": "preview.open", 62 | "enablement": "resourceLangId == vue || preview:isFocused", 63 | "title": "Open preview in browser", 64 | "category": "Preview", 65 | "icon": "$(browser)" 66 | }, 67 | { 68 | "command": "preview.update", 69 | "enablement": "preview:isViteStarted", 70 | "title": "Update @vuedx/preview package", 71 | "category": "Preview", 72 | "icon": "$(arrow-up)" 73 | }, 74 | { 75 | "command": "preview.stop", 76 | "enablement": "preview:isViteStarted", 77 | "title": "Stop preview server", 78 | "category": "Preview", 79 | "icon": "$(stop)" 80 | }, 81 | { 82 | "command": "preview.refresh", 83 | "enablement": "preview:isFocused", 84 | "title": "Referh preview", 85 | "category": "Preview", 86 | "icon": "$(refresh)" 87 | } 88 | ], 89 | "keybindings": [ 90 | { 91 | "command": "preview.refresh", 92 | "key": "ctrl+r", 93 | "mac": "cmd+r", 94 | "when": "preview:isFocused" 95 | } 96 | ], 97 | "menus": { 98 | "editor/title": [ 99 | { 100 | "when": "resourceLangId == vue", 101 | "command": "preview.show", 102 | "group": "navigation" 103 | }, 104 | { 105 | "when": "preview:isFocused", 106 | "command": "preview.showSource", 107 | "group": "navigation" 108 | }, 109 | { 110 | "when": "preview:isFocused", 111 | "command": "preview.refresh", 112 | "group": "navigation" 113 | }, 114 | { 115 | "when": "preview:isFocused || resourceLangId == vue", 116 | "command": "preview.open", 117 | "group": "z_commands" 118 | }, 119 | { 120 | "when": "preview:isFocused && preview:isViteStarted", 121 | "command": "preview.stop", 122 | "group": "z_commands" 123 | } 124 | ] 125 | }, 126 | "languages": [ 127 | { 128 | "id": "vue", 129 | "extensions": [ 130 | ".vue.p" 131 | ] 132 | } 133 | ] 134 | }, 135 | "extensionDependencies": [ 136 | "znck.vue" 137 | ], 138 | "engines": { 139 | "vscode": "^1.63.0" 140 | }, 141 | "devDependencies": { 142 | "@types/node": "^14.14.22", 143 | "@types/node-fetch": "^2.5.8", 144 | "@types/vscode": "^1.63.0", 145 | "@vuedx/preview": "workspace:*", 146 | "get-port": "^5.1.1", 147 | "node-fetch": "^3.2.0", 148 | "semver": "^7.3.5", 149 | "vsce": "^2.6.7" 150 | }, 151 | "scripts": { 152 | "build": "node scripts/build.mjs", 153 | "release": "vsce publish -p ${VSCODE_MARKETPLACE_TOKEN} --packagePath ./preview.vsix", 154 | "pre-release": "vsce publish --pre-release -p ${VSCODE_MARKETPLACE_TOKEN} --packagePath ./preview.vsix" 155 | } 156 | } 157 | -------------------------------------------------------------------------------- /extension/readme.md: -------------------------------------------------------------------------------- 1 | # Preview 2 | 3 | This extension provides quick preview for `.vue` files. 4 | 5 | ## Support 6 | 7 | This extension is part of [VueDX project](https://github.com/znck/vue-developer-experience), maintained by [Rahul Kadyan](https://github.com/znck). You can [💖 sponsor him](https://github.com/sponsors/znck) for continued development of this extension and other VueDX tools. 8 | 9 |
10 |
11 | 12 | --- 13 | 14 | > Made with 💚 for Vue Developers. 15 | > — [Rahul Kadyan](https://znck.me) ([znck0](https://twitter.com/znck0)) 16 | -------------------------------------------------------------------------------- /extension/scripts/build.mjs: -------------------------------------------------------------------------------- 1 | import { execSync } from 'child_process'; 2 | import fetch, { Headers } from 'node-fetch'; 3 | import FS from 'node:fs'; 4 | import Path from 'node:path'; 5 | import semver from 'semver'; 6 | import { fileURLToPath } from 'url'; 7 | 8 | /** 9 | * @param {string} itemName 10 | */ 11 | async function findLatestVersion(itemName) { 12 | const response = await fetch( 13 | 'https://marketplace.visualstudio.com/_apis/public/gallery/extensionquery', 14 | { 15 | method: 'POST', 16 | headers: new Headers({ 17 | Accept: 'application/json;api-version=7.1-preview.1;excludeUrls=true', 18 | 'Content-Type': 'application/json', 19 | }), 20 | body: JSON.stringify({ 21 | assetTypes: null, 22 | filters: [ 23 | { 24 | criteria: [{ filterType: 7, value: itemName }], 25 | direction: 2, 26 | pageSize: 100, 27 | pageNumber: 1, 28 | sortBy: 0, 29 | sortOrder: 0, 30 | pagingToken: null, 31 | }, 32 | ], 33 | flags: 2151, 34 | }), 35 | } 36 | ); 37 | 38 | const body = 39 | /** @type {{results: Array<{extensions: Array<{versions: Array<{version: string}>}>}>}} */ ( 40 | await response.json() 41 | ); 42 | 43 | const extension = body.results 44 | .flatMap((result) => result.extensions) 45 | .find((extension) => extension != null); 46 | 47 | if (extension != null) return extension.versions[0]?.version; 48 | 49 | return undefined; 50 | } 51 | 52 | const fileNames = ['package.json']; 53 | export function getDir() { 54 | const arg = process.argv[2] ?? process.cwd(); 55 | const dir = Path.isAbsolute(arg) ? arg : Path.resolve(process.cwd(), arg); 56 | return dir; 57 | } 58 | 59 | /** 60 | * @param {string} dir 61 | */ 62 | function backup(dir) { 63 | for (const fileName of fileNames) { 64 | const file = Path.resolve(dir, fileName); 65 | const fileBak = Path.resolve(dir, `${fileName}.bak`); 66 | 67 | FS.writeFileSync(fileBak, FS.readFileSync(file, 'utf-8')); 68 | } 69 | } 70 | 71 | /** 72 | * @param {string} dir 73 | */ 74 | function revert(dir) { 75 | for (const fileName of fileNames) { 76 | const file = Path.resolve(dir, fileName); 77 | const fileBak = Path.resolve(dir, `${fileName}.bak`); 78 | 79 | if (FS.existsSync(fileBak)) { 80 | FS.writeFileSync(file, FS.readFileSync(fileBak, 'utf-8')); 81 | FS.unlinkSync(fileBak); 82 | } 83 | } 84 | } 85 | 86 | /** 87 | * @param {string} current 88 | * @param {string} [latest] 89 | */ 90 | function getNextPreReleaseVersion(current, latest) { 91 | let target = current; 92 | const v1 = semver.parse(current); 93 | const v2 = semver.parse(latest); 94 | 95 | if (v1 == null) return semver.inc(target, 'minor'); 96 | if (v2 == null || latest == null) { 97 | return semver.inc(target, v1.minor % 2 === 0 ? 'minor' : 'patch'); 98 | } 99 | 100 | if (v2.compare(v1) > 0) target = latest; 101 | 102 | return semver.inc(target, semver.minor(target) % 2 === 0 ? 'minor' : 'patch'); 103 | } 104 | 105 | /** 106 | * 107 | * @param {string} dir 108 | */ 109 | async function transform(dir) { 110 | const pkg = JSON.parse(FS.readFileSync(`${dir}/package.json`, 'utf-8')); 111 | const RELEASE_CHANNEL = /** @type {'release'|'pre-release'} */ ( 112 | process.env['RELEASE_CHANNEL'] ?? 'release' 113 | ); 114 | 115 | delete pkg.dependencies; 116 | delete pkg.devDependencies; 117 | 118 | if (RELEASE_CHANNEL === 'pre-release') { 119 | pkg['pre-release'] = true; 120 | pkg.version = getNextPreReleaseVersion( 121 | pkg.version, 122 | await findLatestVersion(`${pkg.publisher}.${pkg.name}`) 123 | ); 124 | console.debug('Setting version to', pkg.version); 125 | } else { 126 | if (Array.isArray(pkg.contributions?.jsonValidation)) { 127 | pkg.contributions.jsonValidation[0].url = `https://unpkg.com/@vuedx/projectconfig@${pkg.version}/schema.json`; 128 | } 129 | } 130 | 131 | const packageFile = Path.resolve(dir, 'package.json'); 132 | 133 | FS.writeFileSync(packageFile, JSON.stringify(pkg, null, 2)); 134 | } 135 | 136 | /** 137 | * @param {string} dir 138 | * @param {() => void} fn 139 | */ 140 | async function prepareExtensionForPackaging(dir, fn) { 141 | try { 142 | backup(dir); 143 | await transform(dir); 144 | fn(); 145 | } finally { 146 | revert(dir); 147 | } 148 | } 149 | 150 | const __dirname = Path.dirname(fileURLToPath(import.meta.url)); 151 | const dir = Path.resolve(__dirname, '..'); 152 | prepareExtensionForPackaging(dir, () => { 153 | const execArgs = { stdio: [0, 1, 2], cwd: dir }; 154 | const RELEASE_CHANNEL = /** @type {'release'|'pre-release'} */ ( 155 | process.env['RELEASE_CHANNEL'] ?? 'release' 156 | ); 157 | const args = RELEASE_CHANNEL === 'pre-release' ? '--pre-release' : ''; 158 | 159 | execSync(`$(pnpm bin)/vsce package --no-dependencies ${args} --out preview.vsix`, execArgs); 160 | }); 161 | -------------------------------------------------------------------------------- /extension/src/getWebviewContent.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/triple-slash-reference 2 | /// 3 | 4 | export interface EventData { 5 | kind: 'event'; 6 | payload: { 7 | type: 'keyup' | 'keydown'; 8 | init: KeyboardEventInit; 9 | }; 10 | } 11 | 12 | export function getWebviewContent(body: string): string { 13 | return ` 14 | 15 | 16 | 17 | 18 | Preview 19 | 27 | 28 | 29 | ${body} 30 | 65 | 66 | `; 67 | } 68 | -------------------------------------------------------------------------------- /extension/src/global.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/naming-convention */ 2 | /* eslint-disable no-var */ 3 | declare var __DEV__: boolean; 4 | declare var __PROD__: boolean; 5 | declare var __PREVIEW_INSTALLATION_SOURCE__: string; 6 | -------------------------------------------------------------------------------- /extension/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.base.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /jest.config.js: -------------------------------------------------------------------------------- 1 | /** @type {import('@jest/types').Config.InitialOptions} */ 2 | const config = { 3 | verbose: true, 4 | testMatch: [], 5 | rootDir: __dirname, 6 | moduleFileExtensions: ['ts', 'mjs', 'js', 'cjs', 'json', 'vue'], 7 | projects: ['/packages/*/jest.config.js'], 8 | }; 9 | 10 | module.exports = config; 11 | -------------------------------------------------------------------------------- /lint-staged.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | '**/*.{ts,mjs,cjs,js,vue}': ['eslint --quiet --fix --cache', 'prettier --write'], 3 | '*.{css,md}': ['prettier --write'], 4 | '**/*.{json,graphql}': ['prettier --write'], 5 | '.github/**/*.{yaml,yml}': [ 6 | 'node scripts/prepare-workflows.mjs', 7 | 'git add .github/workflows', 8 | 'prettier --write', 9 | ], 10 | }; 11 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "workspace", 4 | "engines": { 5 | "node": ">=14.0.0" 6 | }, 7 | "devDependencies": { 8 | "@changesets/cli": "^2.20.0", 9 | "@rollup/plugin-commonjs": "^19.0.2", 10 | "@rollup/plugin-node-resolve": "^13.1.3", 11 | "@rollup/plugin-replace": "^2.4.2", 12 | "@rollup/plugin-typescript": "^8.3.0", 13 | "@typescript-eslint/eslint-plugin": "^4.33.0", 14 | "@typescript-eslint/parser": "^4.33.0", 15 | "@vuedx/eslint-config": "^0.0.2", 16 | "@vuedx/monorepo-tools": "^0.2.1", 17 | "eslint": "^7.32.0", 18 | "husky": "^6.0.0", 19 | "jest": "^26.6.3", 20 | "js-yaml": "^4.1.0", 21 | "lint-staged": "^11.2.6", 22 | "prettier": "^2.5.1", 23 | "rollup": "^2.66.1", 24 | "ts-jest": "^26.5.6", 25 | "tslib": "^2.3.1", 26 | "typescript": "4.3.2" 27 | }, 28 | "scripts": { 29 | "build": "rollup -c --environment BUILD:production && pnpm recursive --filter ./packages/preview-shell run build", 30 | "dev:build": "rollup -c --environment BUILD:development", 31 | "watch": "rollup -c -w", 32 | "test": "jest", 33 | "coverage": "jest --coverage", 34 | "start": "node packages/preview/bin/preview.js packages/example", 35 | "changeset": "changeset", 36 | "prepare": "husky install" 37 | }, 38 | "pnpm": { 39 | "overrides": { 40 | "vite": "2.5.0", 41 | "typescript": "4.3.2" 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /packages/preview-compiler/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @vuedx/preview-compiler 2 | 3 | ## 0.2.2 4 | 5 | ### Patch Changes 6 | 7 | - dd448e6: Support async imports in `` blocks 8 | - dd448e6: Sync color-scheme with VS Code 9 | 10 | ## 0.2.1 11 | 12 | ### Patch Changes 13 | 14 | - b0eea6a: Build using @vuedx/monorepo-tools 15 | 16 | ## 0.2.0 17 | 18 | ### Minor Changes 19 | 20 | - b03452d: Add HMR support 21 | 22 | ## 0.1.3 23 | 24 | ### Patch Changes 25 | 26 | - 1b39181: Bump all versions to test continuous release CI 27 | 28 | ## 0.1.2 29 | 30 | ### Patch Changes 31 | 32 | - 18a1b02: Bump version 33 | 34 | ## 0.1.1 35 | 36 | ### Patch Changes 37 | 38 | - e3ba132: Update HMR API 39 | 40 | - Version lock on vite@2.0.0-beta.44 41 | - Remove forked HMR client and use `/@vite/client` instead 42 | 43 | ## 0.1.0 44 | 45 | ### Minor Changes 46 | 47 | - d34a262: VS Code preview extension 48 | -------------------------------------------------------------------------------- /packages/preview-compiler/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vuedx/preview-compiler", 3 | "version": "0.2.2", 4 | "main": "dist/preview-compiler.js", 5 | "module": "dist/preview-compiler.esm.js", 6 | "types": "src/index.ts", 7 | "publishConfig": { 8 | "types": "dist/preview-compiler.d.ts" 9 | }, 10 | "files": [ 11 | "dist" 12 | ], 13 | "dependencies": { 14 | "@vue/compiler-dom": "^3.0.5", 15 | "@vuedx/template-ast-types": "^0.6.0" 16 | }, 17 | "devDependencies": { 18 | "@vue/compiler-core": "^3.0.5", 19 | "typescript": "^4.1.3" 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /packages/preview-compiler/src/index.ts: -------------------------------------------------------------------------------- 1 | import type { NodeTransform } from '@vue/compiler-core'; 2 | import { compile as baseCompile } from '@vue/compiler-dom'; 3 | import { 4 | isAttributeNode, 5 | isDirectiveNode, 6 | isElementNode, 7 | isRootNode, 8 | isSimpleExpressionNode, 9 | } from '@vuedx/template-ast-types'; 10 | import * as Path from 'path'; 11 | 12 | interface SetupOutput { 13 | components: string; 14 | requests: string; 15 | state: string; 16 | async?: boolean; 17 | } 18 | 19 | function createPreviewSetupTransform(output: SetupOutput): NodeTransform { 20 | return (node, context) => { 21 | if (isRootNode(node)) { 22 | context.addIdentifiers('$p'); 23 | } else if (isRootNode(context.parent) && isElementNode(node) && node.tag === 'setup') { 24 | context.removeNode(); 25 | 26 | node.props.forEach((prop) => { 27 | if (isAttributeNode(prop)) { 28 | output.async = prop.value != null ? prop.value.content.toLowerCase() === 'true' : true; 29 | } else if (isDirectiveNode(prop) && prop.name === 'bind') { 30 | if (isSimpleExpressionNode(prop.arg) && prop.arg.isStatic) { 31 | if ( 32 | prop.arg.content === 'components' || 33 | prop.arg.content === 'requests' || 34 | prop.arg.content === 'state' 35 | ) { 36 | if (prop.exp != null) { 37 | output[prop.arg.content] = prop.exp.loc.source; 38 | } 39 | } 40 | } 41 | } 42 | }); 43 | } 44 | }; 45 | } 46 | 47 | export interface CompileOptions { 48 | componentFileName: string; 49 | allowOverrides?: boolean | string; 50 | attrs?: Record; 51 | imports?: Record; 52 | hmrId?: string; 53 | } 54 | 55 | export function compile( 56 | content: string, 57 | { componentFileName, hmrId, allowOverrides, attrs = {}, imports = {} }: CompileOptions 58 | ): string { 59 | const setup: SetupOutput = { 60 | components: '{}', 61 | requests: '{}', 62 | state: '{}', 63 | }; 64 | const result = baseCompile(content, { 65 | inline: false, 66 | mode: 'module', 67 | sourceMap: false, 68 | hoistStatic: true, 69 | cacheHandlers: true, 70 | expressionPlugins: ['typescript', 'dynamicImport'], 71 | nodeTransforms: [createPreviewSetupTransform(setup)], 72 | }); 73 | const componentName = (componentFileName.split(Path.sep).pop() ?? 'self').replace(/\.vue$/, ''); 74 | 75 | const preamble = getCode( 76 | result.preamble, 77 | `import * as _Vue from ${JSON.stringify(imports['vue'] ?? 'vue')}`, 78 | `import * as _Preview from ${JSON.stringify( 79 | imports['@vuedx/preview-provider'] ?? '@vuedx/preview-provider' 80 | )}`, 81 | `import _component_self from '${componentFileName.replace(/\\/g, '/')}'`, 82 | `_Preview.installFetchInterceptor()`, 83 | result.code 84 | ); 85 | 86 | const source = `_Vue.defineComponent({ 87 | name: 'Preview(${componentName}):${String(attrs['name'] ?? 'unnamed')}', 88 | inheritAttrs: false, 89 | _file: ${JSON.stringify(componentFileName)}, 90 | components: { "${componentName}": _component_self }, 91 | ${setup.async === true ? 'async ' : ''}setup() { 92 | _Preview.setActiveComponent({ 93 | ...(${JSON.stringify(attrs)}), 94 | componentName: "${componentName}", 95 | }) 96 | const $p = { 97 | ..._Preview.provider, 98 | attrs: ${JSON.stringify(attrs)}, 99 | state: _Vue.reactive(_overrides.state != null ? _overrides.state : ${setup.state}), 100 | x: _Vue.inject('preview:UserProviders', null), 101 | } 102 | 103 | _Preview.useRequests({ ...(${setup.requests}), ..._overrides.requests }) 104 | _Preview.useComponents({...(${setup.components}), ..._overrides.components}) 105 | 106 | return { preview: $p } 107 | }, 108 | created() { 109 | this.$p = this.preview 110 | }, 111 | render, 112 | })`.trim(); 113 | 114 | if (hmrId != null) { 115 | return getCode( 116 | preamble, 117 | `const _overrides = {}`, 118 | `const _preview_main = ${source}`, 119 | generateHMR(hmrId), 120 | `export default _preview_main` 121 | ); 122 | } else if (allowOverrides != null) { 123 | const fn = typeof allowOverrides === 'string' ? allowOverrides : ''; 124 | return getCode(preamble, `export default (_overrides = {}) => ${fn}(${source})`); 125 | } else { 126 | return getCode(preamble, `export default (${source})`); 127 | } 128 | } 129 | 130 | function generateHMR(hmrId: string): string { 131 | return ` 132 | _preview_main.__hmrId = '${hmrId}' 133 | typeof __VUE_HMR_RUNTIME__ !== 'undefined' && __VUE_HMR_RUNTIME__.createRecord(_preview_main.__hmrId, _preview_main) 134 | if (import.meta.hot) { 135 | import.meta.hot.accept(({ default: updated }) => { 136 | __VUE_HMR_RUNTIME__.reload(updated.__hmrId, updated) 137 | }) 138 | }`.trim(); 139 | } 140 | 141 | function getCode(...lines: Array): string { 142 | return lines.filter(Boolean).join('\n'); 143 | } 144 | -------------------------------------------------------------------------------- /packages/preview-compiler/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src"] 4 | } 5 | -------------------------------------------------------------------------------- /packages/preview-provider/.npmignore: -------------------------------------------------------------------------------- 1 | dist/types/ 2 | -------------------------------------------------------------------------------- /packages/preview-provider/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @vuedx/preview-provider 2 | 3 | ## 0.1.5 4 | 5 | ### Patch Changes 6 | 7 | - dd448e6: Support async imports in `` blocks 8 | - dd448e6: Sync color-scheme with VS Code 9 | 10 | ## 0.1.4 11 | 12 | ### Patch Changes 13 | 14 | - b0eea6a: Build using @vuedx/monorepo-tools 15 | 16 | ## 0.1.3 17 | 18 | ### Patch Changes 19 | 20 | - 1b39181: Bump all versions to test continuous release CI 21 | 22 | ## 0.1.2 23 | 24 | ### Patch Changes 25 | 26 | - 18a1b02: Bump version 27 | 28 | ## 0.1.1 29 | 30 | ### Patch Changes 31 | 32 | - e3ba132: Update HMR API 33 | 34 | - Version lock on vite@2.0.0-beta.44 35 | - Remove forked HMR client and use `/@vite/client` instead 36 | 37 | - e3ba132: Use `vue` instead of `@vue/runtime-core` 38 | 39 | ## 0.1.0 40 | 41 | ### Minor Changes 42 | 43 | - d34a262: VS Code preview extension 44 | -------------------------------------------------------------------------------- /packages/preview-provider/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vuedx/preview-provider", 3 | "version": "0.1.5", 4 | "peerDependencies": { 5 | "vue": "^3.0.5" 6 | }, 7 | "peerDependenciesMeta": { 8 | "vue": { 9 | "optional": true 10 | } 11 | }, 12 | "main": "dist/preview-provider.js", 13 | "module": "dist/preview-provider.mjs", 14 | "types": "src/index.ts", 15 | "publishConfig": { 16 | "types": "dist/preview-provider.d.ts" 17 | }, 18 | "buildConfig": { 19 | "external": [ 20 | "vue" 21 | ] 22 | }, 23 | "files": [ 24 | "dist" 25 | ], 26 | "devDependencies": { 27 | "typescript": "^4.1.3", 28 | "vue": "^3.0.5" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /packages/preview-provider/src/activeComponent.ts: -------------------------------------------------------------------------------- 1 | export interface ActiveComponent { 2 | name?: string; 3 | componentName: string; 4 | } 5 | 6 | let activeComponent: ActiveComponent = { 7 | componentName: '', 8 | }; 9 | 10 | export function setActiveComponent(component: ActiveComponent): void { 11 | activeComponent = component; 12 | } 13 | 14 | export function getActiveComponent(): ActiveComponent { 15 | return activeComponent; 16 | } 17 | -------------------------------------------------------------------------------- /packages/preview-provider/src/communication.ts: -------------------------------------------------------------------------------- 1 | export function notify( 2 | event: 'missing-request-handler', 3 | payload: any 4 | ): void; 5 | 6 | export function notify(event: string, payload: any): void { 7 | console.log('[preview]', event, payload); 8 | window.dispatchEvent(new CustomEvent('preview:notify', { detail: { event, payload } })); 9 | } 10 | -------------------------------------------------------------------------------- /packages/preview-provider/src/components.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error 2 | // @ts-ignore - export * is not supported from rollup-plugin-dts 3 | import { Component, defineAsyncComponent, getCurrentInstance } from 'vue'; 4 | 5 | export function useComponents(components: Record): void { 6 | const instance = getCurrentInstance(); 7 | if (instance != null) { 8 | const { app } = instance.appContext; 9 | 10 | Object.entries(components).forEach(([name, component]) => { 11 | app.component( 12 | name, 13 | typeof component === 'function' ? defineAsyncComponent(component as any) : component 14 | ); 15 | }); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /packages/preview-provider/src/fetch.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error 2 | // @ts-ignore - rollup-plugin-dts does not work with export * 3 | import { getCurrentInstance, onUnmounted } from 'vue'; 4 | import { getActiveComponent } from './activeComponent'; 5 | import { notify } from './communication'; 6 | type RequestHandler = (request: Request) => any; 7 | 8 | export type RequestOptions = Record>; 9 | 10 | interface InterceptorRecord { 11 | name: string; 12 | matcher(request: Request): Promise | boolean; 13 | handler: RequestHandler; 14 | } 15 | 16 | const state: { interceptors: InterceptorRecord[]; warned: Set } = { 17 | interceptors: [], 18 | warned: new Set('/'), 19 | }; 20 | const REQUEST_RE = /^(GET|POST|PUT|DELETE|HEAD)(\|(GET|POST|PUT|DELETE|HEAD))*\s+/i; 21 | const GRAPHQL_RE = /^(QUERY|MUTATION)\s+/i; 22 | 23 | /** 24 | * @param options register request handlers/interceptors. 25 | */ 26 | export function useRequests(options: RequestOptions): void { 27 | state.interceptors = Object.entries(options).map(([key, value]): InterceptorRecord => { 28 | const handler = (typeof value === 'function' ? value : () => value) as any; 29 | const graphql = GRAPHQL_RE.exec(key); 30 | if (graphql != null) { 31 | const [type, url, pattern] = key.split(/[ ]+/) as [string, string] | [string, string, string]; 32 | return { 33 | name: key, 34 | matcher: async (request) => { 35 | if (!matches(request.url, url)) return false; 36 | 37 | let query: string | null = null; 38 | if (type?.toUpperCase() === 'QUERY') { 39 | if (request.method === 'GET') { 40 | query = getSearchParams(request.url).get('query'); 41 | } 42 | } 43 | 44 | if (request.method === 'POST') { 45 | try { 46 | const body = await request.clone().json(); 47 | query = typeof body.query === 'string' ? body.query : null; 48 | } catch {} 49 | } 50 | 51 | if (query != null) { 52 | if (pattern == null) return true; 53 | else 54 | return matchPattern(query.replace(/[ \r\n]/g, ''), pattern.replace(/[ \r\n]/g, '')); 55 | } 56 | 57 | return false; 58 | }, 59 | handler, 60 | }; 61 | } 62 | const http = REQUEST_RE.exec(key); 63 | if (http != null) { 64 | const [type, url] = key.split(/[ ]+/) as [string, string]; 65 | const methods = new Set(type.toUpperCase().split('|')); 66 | 67 | console.log(http); 68 | 69 | return { 70 | name: key, 71 | matcher: (request) => methods.has(request.method) && matches(request.url, url), 72 | handler, 73 | }; 74 | } 75 | 76 | return { 77 | name: key, 78 | matcher: (request) => { 79 | return matches(request.url, key); 80 | }, 81 | handler, 82 | }; 83 | }); 84 | 85 | if (getCurrentInstance() != null) { 86 | onUnmounted(() => { 87 | state.interceptors = []; 88 | }); 89 | } 90 | } 91 | 92 | function matches(url: string, pattern: string): boolean { 93 | if (pattern === '*') return true; 94 | if (pattern.includes('*')) { 95 | return matchPattern(pattern.startsWith('/') ? getPathName(url) : url, pattern); 96 | } 97 | if (pattern.startsWith('/')) { 98 | return getPathName(url) === pattern; 99 | } 100 | 101 | return url === pattern; 102 | } 103 | 104 | function matchPattern(text: string, pattern: string): boolean { 105 | if (pattern.includes('*')) { 106 | const RE = new RegExp(`^${pattern.replace(/\*/g, '.*?')}$`); 107 | 108 | return RE.test(text); 109 | } else { 110 | return text === pattern; 111 | } 112 | } 113 | 114 | /** 115 | * Install fetch interceptors. 116 | */ 117 | export function installFetchInterceptor(): void { 118 | const fetch = window.fetch; 119 | 120 | window.fetch = async function (input: RequestInfo, init?: RequestInit): Promise { 121 | const request = 122 | input instanceof Request ? new Request(input.clone(), init) : new Request(input, init); 123 | const interceptor = await getInterceptor(request); 124 | 125 | if (interceptor != null) { 126 | const active = getActiveComponent(); 127 | const group = active.name != null ? `[${active.name}] ` : ''; 128 | console.groupCollapsed(`${group}Request handled by: ${interceptor.name}`); 129 | console.debug(request); 130 | console.groupEnd(); 131 | const result = await interceptor.handler(request); 132 | const encode = (result: unknown): Response => { 133 | if (result instanceof Response) return result; 134 | else if (typeof result === 'string') 135 | return new Response(result, { 136 | status: 200, 137 | statusText: 'OK', 138 | headers: { 'Content-Type': 'text/plain' }, 139 | }); 140 | else 141 | return new Response(JSON.stringify(result), { 142 | status: 200, 143 | statusText: 'OK', 144 | headers: { 'Content-Type': 'application/json' }, 145 | }); 146 | }; 147 | 148 | const response = encode(result.default != null ? result.default : result); 149 | 150 | const copy = response.clone(); 151 | 152 | const body = 153 | copy.headers.get('Content-Type') === 'application/json' 154 | ? await copy.json() 155 | : await copy.text(); 156 | 157 | console.groupCollapsed(`${group}Response from: ${interceptor.name}`); 158 | console.debug(copy); 159 | console.debug(body); 160 | console.groupEnd(); 161 | return response; 162 | } 163 | 164 | const id = `${request.method} ${request.url}`; 165 | if (!state.warned.has(id)) { 166 | state.warned.add(id); 167 | notify('missing-request-handler', { request, body: await request.clone().text() }); 168 | } 169 | 170 | return fetch(request); 171 | }; 172 | } 173 | 174 | async function getInterceptor(request: Request): Promise { 175 | for (const interceptor of state.interceptors) { 176 | if (await interceptor.matcher(request)) { 177 | return interceptor; 178 | } 179 | } 180 | 181 | return null; 182 | } 183 | 184 | function getPathName(url: string): string { 185 | try { 186 | return new URL(url).pathname; 187 | } catch { 188 | return url.replace(/^[^/]+:\/\/[^/]+/, ''); 189 | } 190 | } 191 | 192 | function getSearchParams(url: string): URLSearchParams { 193 | try { 194 | return new URL(url).searchParams; 195 | } catch { 196 | const index = url.indexOf('?'); 197 | 198 | return index < 0 ? new URLSearchParams() : new URLSearchParams(url.substr(index + 1)); 199 | } 200 | } 201 | -------------------------------------------------------------------------------- /packages/preview-provider/src/index.ts: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error 2 | // @ts-ignore - export * is not supported from rollup-plugin-dts 3 | import type { Component } from 'vue'; 4 | import { getActiveComponent, setActiveComponent } from './activeComponent'; 5 | import { useComponents } from './components'; 6 | import { installFetchInterceptor, RequestOptions, useRequests } from './fetch'; 7 | import { provider } from './utilities'; 8 | 9 | export interface SetupOptions { 10 | requests: RequestOptions; 11 | components: Record; 12 | state: T; 13 | } 14 | 15 | export { 16 | provider, 17 | useRequests, 18 | useComponents, 19 | installFetchInterceptor, 20 | setActiveComponent, 21 | getActiveComponent, 22 | }; 23 | -------------------------------------------------------------------------------- /packages/preview-provider/src/utilities.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/prefer-ts-expect-error */ 2 | // @ts-ignore - export * is not supported from rollup-plugin-dts 3 | import { Component, defineComponent, h } from 'vue'; 4 | 5 | export function repeat(count: number, generator: (index: number) => T): T[] { 6 | const items: T[] = []; 7 | for (let i = 0; i < count; ++i) { 8 | items.push(generator(i)); 9 | } 10 | return items; 11 | } 12 | 13 | export function join(items: any[], glue: string = ' '): string { 14 | return items.filter((item) => item == null).join(glue); 15 | } 16 | 17 | export function createFunctionObject(fn: F, ob: O): F & O { 18 | return Object.assign(fn, ob); 19 | } 20 | 21 | /** 22 | * A collection of string generators. 23 | */ 24 | export const string = createFunctionObject(() => '', { 25 | /** 26 | * Get a random person's name. 27 | */ 28 | person: createFunctionObject( 29 | () => join([string.person.firstName(), string.person.middleName(), string.person.lastName()]), 30 | { 31 | firstName: () => '', 32 | middleName: () => '', 33 | lastName: () => '', 34 | } 35 | ), 36 | }); 37 | 38 | /** 39 | * A collection of number generators. 40 | */ 41 | export const number = createFunctionObject(() => number.any(), { 42 | any: () => (Math.random() <= 0.5 ? number.negative() : number.positive()), 43 | positive: () => Math.random() * Number.MAX_VALUE, 44 | negative: () => Math.random() * Number.MIN_VALUE, 45 | in: (start: number, end: number) => Math.min(start, end) + Math.abs(end - start) * Math.random(), 46 | int: createFunctionObject(() => number.int.any(), { 47 | any: () => (Math.random() <= 0.5 ? number.int.negative() : number.int.positive()), 48 | positive: () => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER), 49 | negative: () => Math.ceil(Math.random() * Number.MIN_SAFE_INTEGER), 50 | in: (start: number, end: number) => 51 | Math.floor(Math.min(start, end) + Math.abs(end - start) * Math.random()), 52 | }), 53 | 54 | percentage: () => number.in(0, 100), 55 | }); 56 | 57 | export const bool = createFunctionObject(() => Math.random() <= 0.5, {}); 58 | export const on = createFunctionObject( 59 | (name: string) => (event: any) => console.log(name, event), 60 | {} 61 | ); 62 | 63 | export function defineStubComponent(name: string, component: Component): Component { 64 | return defineComponent({ 65 | inheritAttrs: false, 66 | name: `stub-${name}`, 67 | // eslint-disable-next-line @typescript-eslint/prefer-ts-expect-error 68 | // @ts-ignore — rollup-pugin-dts 69 | setup: (props, { slots, attrs }) => { 70 | return () => 71 | h( 72 | 'div', 73 | { 74 | style: ` 75 | background: #F7E9D4; 76 | color: #B27603; 77 | display: inline-block; 78 | padding: 4px 8px; 79 | border: 1px dashed #B27603; 80 | box-sizing: border-box; 81 | `, 82 | }, 83 | [h(component, { ...attrs, ...props } as any, slots)] 84 | ); 85 | }, 86 | }); 87 | } 88 | 89 | export const stub = createFunctionObject( 90 | (content: string = 'stubbed component'): Component => stub.static(content), 91 | { 92 | static: (content: string): Component => 93 | defineStubComponent('anonymous', defineComponent({ render: () => content })), 94 | showProps: (): Component => 95 | defineStubComponent( 96 | 'anonymous', 97 | // prettier-ignore 98 | // @ts-ignore - rollup-plugin-dts does not work with export * 99 | defineComponent((_, { attrs }) => () => 100 | h('pre', null, JSON.stringify(attrs, null, 2)) 101 | ) 102 | ), 103 | } 104 | ); 105 | 106 | export const component = createFunctionObject( 107 | (): Component => defineComponent(() => () => h('div')), 108 | { 109 | image: createFunctionObject( 110 | (src?: string): Component => defineComponent(() => () => h('img', { src })), 111 | { 112 | unsplash: (query: string = 'random'): Component => 113 | component.image(`https://unsplash.it/?q=${query}&id=${number.int.in(0, 50)}`), 114 | } 115 | ), 116 | } 117 | ); 118 | 119 | const STATUS_TEXTS: Record = { 120 | 100: 'Continue', 121 | 101: 'Switching Protocols', 122 | 102: 'Processing', 123 | 103: 'Early Hints', 124 | 200: 'OK', 125 | 201: 'Created', 126 | 202: 'Accepted', 127 | 203: 'Non-Authoritative Information', 128 | 204: 'No Content', 129 | 205: 'Reset Content', 130 | 206: 'Partial Content', 131 | 207: 'Multi-Status', 132 | 208: 'Already Reported', 133 | 218: 'This is fine', // Apache 134 | 226: 'IM Used', 135 | 300: 'Multiple Choices', 136 | 301: 'Moved Permanently', 137 | 302: 'Found', 138 | 303: 'See Other', 139 | 304: 'Not Modified', 140 | 305: 'Use Proxy', 141 | 306: 'Switch Proxy', 142 | 307: 'Temporary Redirect', 143 | 308: 'Permanent Redirect', 144 | 400: 'Bad Request', 145 | 401: 'Unauthorized', 146 | 402: 'Payment Required', 147 | 403: 'Forbidden', 148 | 404: 'Not Found', 149 | 405: 'Method Not Allowed', 150 | 406: 'Not Acceptable', 151 | 407: 'Proxy Authentication Required', 152 | 408: 'Request Timeout', 153 | 409: 'Conflict', 154 | 410: 'Gone', 155 | 411: 'Length Required', 156 | 413: 'Payload Too Large', 157 | 414: 'URI Too Long', 158 | 415: 'Unsupported Media Type ', 159 | 416: 'Range Not Satisfiable', 160 | 417: 'Expectation Failed', 161 | 418: "I'm a teapot", 162 | 419: 'Page Expired', // Laravel 163 | 420: 'Method Failure', // Spring 164 | 421: 'Misdirected Request', 165 | 422: 'Unprocessable Entity', 166 | 423: 'Locked', 167 | 424: 'Failed Dependency', 168 | 425: 'Too Early', 169 | 426: 'Upgrade Required', 170 | 428: 'Precondition Required', 171 | 429: 'Too Many Requests', 172 | 431: 'Request Header Fields Too Large', 173 | 450: 'Blocked by Windows Parental Controls', // Microsoft 174 | 451: 'Unavailable For Legal Reasons', 175 | 500: 'Internal Server Error', 176 | 501: 'Not Implemented', 177 | 502: 'Bad Gateway', 178 | 503: 'Service Unavailable', 179 | 504: 'Gateway Timeout', 180 | 505: 'HTTP Version Not Supported', 181 | 506: 'Variant Also Negotiates', 182 | 507: 'Insufficient Storage', 183 | 508: 'Loop Detected', 184 | 510: 'Not Extended', 185 | 511: 'Network Authentication Required', 186 | }; 187 | 188 | export const http = createFunctionObject( 189 | (body: BodyInit = '{}', status: number = 200) => http.send(body, status), 190 | { 191 | status: (status: number = 200) => 192 | new Response(null, { status, statusText: STATUS_TEXTS[status] }), 193 | send: (body: BodyInit, status: number = 200) => 194 | new Response(body, { status, statusText: STATUS_TEXTS[status] }), 195 | create: (body?: BodyInit, init?: ResponseInit) => new Response(body, init), 196 | delayed: async (delay: number, body?: BodyInit, init?: ResponseInit) => { 197 | return await new Promise((resolve) => { 198 | if (Number.isFinite(delay)) { 199 | setTimeout(() => { 200 | resolve(new Response(body, init)); 201 | }, delay); 202 | } 203 | }); 204 | }, 205 | } 206 | ); 207 | 208 | export const provider = { http, stub, component, number, string, bool, repeat, on }; 209 | -------------------------------------------------------------------------------- /packages/preview-provider/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.base.json", 3 | "include": ["src"], 4 | "compilerOptions": { 5 | "lib": ["ESNext", "DOM"] 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /packages/preview-shell/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # @vuedx/preview-shell 2 | 3 | ## 0.3.0 4 | 5 | ### Minor Changes 6 | 7 | - ff930e3: Use `/__preview` path prefix for plugin mode 8 | 9 | BREAKING CHANGE: Internal virtual files also use `__preview` prefix, instead of `@preview`. 10 | 11 | ## 0.2.2 12 | 13 | ### Patch Changes 14 | 15 | - dd448e6: Support async imports in `` blocks 16 | - dd448e6: Sync color-scheme with VS Code 17 | 18 | ## 0.2.1 19 | 20 | ### Patch Changes 21 | 22 | - b0eea6a: Build using @vuedx/monorepo-tools 23 | 24 | ## 0.2.0 25 | 26 | ### Minor Changes 27 | 28 | - b03452d: Add HMR support 29 | 30 | ## 0.1.4 31 | 32 | ### Patch Changes 33 | 34 | - 83e89e5: Use consistent virtual resource scheme 35 | 36 | - Use `@preview:component/${type}.${ext}` for component scoped resources 37 | - Use `@preview:shell/` for proxying pre-built shell application 38 | - Use `@preview:components.js` for component index 39 | - Use `@preview:user/setup.js` for custom runtime setup file 40 | 41 | ## 0.1.3 42 | 43 | ### Patch Changes 44 | 45 | - 1b39181: Bump all versions to test continuous release CI 46 | 47 | ## 0.1.2 48 | 49 | ### Patch Changes 50 | 51 | - 18a1b02: Fix build in release pipeline 52 | 53 | ## 0.1.1 54 | 55 | ### Patch Changes 56 | 57 | - e3ba132: Update HMR API 58 | 59 | - Version lock on vite@2.0.0-beta.44 60 | - Remove forked HMR client and use `/@vite/client` instead 61 | 62 | ## 0.1.0 63 | 64 | ### Minor Changes 65 | 66 | - d34a262: VS Code preview extension 67 | -------------------------------------------------------------------------------- /packages/preview-shell/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Preview 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /packages/preview-shell/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@vuedx/preview-shell", 3 | "version": "0.3.0", 4 | "scripts": { 5 | "start": "vite serve", 6 | "build": "vite build --base /__preview:shell/" 7 | }, 8 | "files": [ 9 | "dist" 10 | ], 11 | "buildConfig": { 12 | "useMain": false 13 | }, 14 | "dependencies": { 15 | "vue": "^3.2.29", 16 | "vue-router": "^4.0.12" 17 | }, 18 | "devDependencies": { 19 | "@vitejs/plugin-vue": "^1.4.0", 20 | "@vue/compiler-sfc": "^3.2.4", 21 | "autoprefixer": "^10.2.3", 22 | "browserlist": "^1.0.1", 23 | "magic-string": "^0.25.7", 24 | "postcss": "^8.3.6", 25 | "tailwindcss": "^2.0.2", 26 | "typescript": "^4.1.3", 27 | "vite": "^2.5.0" 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /packages/preview-shell/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | }, 6 | }; 7 | -------------------------------------------------------------------------------- /packages/preview-shell/public/browserconfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | #ffffff 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /packages/preview-shell/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/favicon.ico -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/android-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/android-icon-144x144.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/android-icon-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/android-icon-192x192.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/android-icon-36x36.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/android-icon-36x36.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/android-icon-48x48.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/android-icon-48x48.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/android-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/android-icon-72x72.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/android-icon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/android-icon-96x96.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon-114x114.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon-114x114.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon-120x120.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon-120x120.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon-144x144.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon-152x152.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon-152x152.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon-180x180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon-180x180.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon-57x57.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon-57x57.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon-60x60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon-60x60.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon-72x72.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon-72x72.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon-76x76.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon-76x76.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon-precomposed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon-precomposed.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/apple-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/apple-icon.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/favicon-16x16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/favicon-16x16.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/favicon-32x32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/favicon-32x32.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/favicon-96x96.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/favicon-96x96.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/ms-icon-144x144.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/ms-icon-144x144.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/ms-icon-150x150.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/ms-icon-150x150.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/ms-icon-310x310.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/ms-icon-310x310.png -------------------------------------------------------------------------------- /packages/preview-shell/public/icons/ms-icon-70x70.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/public/icons/ms-icon-70x70.png -------------------------------------------------------------------------------- /packages/preview-shell/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Preview", 3 | "icons": [ 4 | { 5 | "src": "\/icons\/android-icon-36x36.png", 6 | "sizes": "36x36", 7 | "type": "image\/png", 8 | "density": "0.75" 9 | }, 10 | { 11 | "src": "\/icons\/android-icon-48x48.png", 12 | "sizes": "48x48", 13 | "type": "image\/png", 14 | "density": "1.0" 15 | }, 16 | { 17 | "src": "\/icons\/android-icon-72x72.png", 18 | "sizes": "72x72", 19 | "type": "image\/png", 20 | "density": "1.5" 21 | }, 22 | { 23 | "src": "\/icons\/android-icon-96x96.png", 24 | "sizes": "96x96", 25 | "type": "image\/png", 26 | "density": "2.0" 27 | }, 28 | { 29 | "src": "\/icons\/android-icon-144x144.png", 30 | "sizes": "144x144", 31 | "type": "image\/png", 32 | "density": "3.0" 33 | }, 34 | { 35 | "src": "\/icons\/android-icon-192x192.png", 36 | "sizes": "192x192", 37 | "type": "image\/png", 38 | "density": "4.0" 39 | } 40 | ] 41 | } 42 | -------------------------------------------------------------------------------- /packages/preview-shell/src/Root.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 12 | 17 | -------------------------------------------------------------------------------- /packages/preview-shell/src/app.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | -------------------------------------------------------------------------------- /packages/preview-shell/src/app.ts: -------------------------------------------------------------------------------- 1 | import './app.css'; 2 | import { createApp } from 'vue'; 3 | import Root from './Root.vue'; 4 | import { router } from './router'; 5 | 6 | Root.name = 'Preview'; 7 | const app = createApp(Root); 8 | 9 | app.use(router); 10 | 11 | export { app }; 12 | -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/MacBook-Pro-16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/src/assets/MacBook-Pro-16.png -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/assets.d.ts: -------------------------------------------------------------------------------- 1 | declare module '*.png' { 2 | const value: string; 3 | export default value; 4 | } 5 | declare module '*.svg' { 6 | const value: string; 7 | export default value; 8 | } 9 | -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/device-freeform.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/iPad-Pro-13-Landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/src/assets/iPad-Pro-13-Landscape.png -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/iPad-Pro-13-Landscape.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/iPad-Pro-13-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/src/assets/iPad-Pro-13-Portrait.png -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/iPad-Pro-13-Portrait.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/iPhone-11-Landscape.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/src/assets/iPhone-11-Landscape.png -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/iPhone-11-Landscape.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/iPhone-11-Portrait.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/vuedx/preview/d47255746d42a5a423037718ef8d8b62b5a692f0/packages/preview-shell/src/assets/iPhone-11-Portrait.png -------------------------------------------------------------------------------- /packages/preview-shell/src/assets/iPhone-11-Portrait.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /packages/preview-shell/src/components.ts: -------------------------------------------------------------------------------- 1 | import { ref } from 'vue'; 2 | 3 | interface PreviewMetadata { 4 | id: number; 5 | name: string; 6 | device: string; 7 | deviceProps: Record; 8 | } 9 | 10 | export interface ComponentMetadata { 11 | id: string; 12 | name: string; 13 | path: string; 14 | previews: PreviewMetadata[]; 15 | } 16 | 17 | export const components = ref((window as any).components ?? []); 18 | 19 | window.addEventListener('preview:components' as any, (event: CustomEvent) => { 20 | components.value = event.detail; 21 | }); 22 | 23 | if (import.meta.env.DEV) { 24 | components.value = [ 25 | { 26 | id: 'component/Alert', 27 | name: 'Alert', 28 | path: 'component/Alert.vue', 29 | previews: [ 30 | { id: 1, name: 'One', device: 'freeform', deviceProps: { controls: true } }, 31 | { id: 2, name: 'Two', device: 'mobile', deviceProps: {} }, 32 | { id: 3, name: 'Three', device: 'desktop', deviceProps: {} }, 33 | ], 34 | }, 35 | { 36 | id: 'component/Button.vue', 37 | name: 'Button', 38 | path: 'component/in-a-very/very/very/very/deep/directory/Button.vue', 39 | previews: [ 40 | { id: 1, name: 'One', device: 'freeform', deviceProps: { controls: true } }, 41 | { id: 2, name: 'Two', device: 'mobile', deviceProps: {} }, 42 | { id: 3, name: 'Three', device: 'desktop', deviceProps: {} }, 43 | ], 44 | }, 45 | 46 | ...Array(30) 47 | .fill(null) 48 | .map((_, i) => ({ 49 | id: `component/Example${i}`, 50 | name: `Example${i}`, 51 | path: `components/${i}/Example${i}.vue`, 52 | previews: [ 53 | { id: 1, name: 'One', device: 'freeform', deviceProps: { controls: true } }, 54 | { id: 2, name: 'Two', device: 'mobile', deviceProps: {} }, 55 | { id: 3, name: 'Three', device: 'desktop', deviceProps: {} }, 56 | ] as PreviewMetadata[], 57 | })), 58 | ].sort(() => (Math.random() > 0.5 ? 1 : -1)); 59 | } 60 | -------------------------------------------------------------------------------- /packages/preview-shell/src/components/BaseDevice.vue: -------------------------------------------------------------------------------- 1 | 19 | 20 | 43 | 44 | 82 | -------------------------------------------------------------------------------- /packages/preview-shell/src/components/Browser.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 24 | 25 | 34 | -------------------------------------------------------------------------------- /packages/preview-shell/src/components/ConfiguredDevice.vue: -------------------------------------------------------------------------------- 1 | 85 | 86 | 133 | 134 | 161 | -------------------------------------------------------------------------------- /packages/preview-shell/src/components/Content.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 |