├── .eslintrc.json ├── .gitignore ├── .npmignore ├── LICENSE ├── README.md ├── package.json ├── packages ├── examples │ ├── js │ │ ├── react-mpa │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ ├── favicon.ico │ │ │ │ ├── index.html │ │ │ │ ├── logo192.png │ │ │ │ ├── logo512.png │ │ │ │ ├── manifest.json │ │ │ │ └── robots.txt │ │ │ └── src │ │ │ │ ├── assets │ │ │ │ └── logo.svg │ │ │ │ └── pages │ │ │ │ └── home │ │ │ │ ├── App.jsx │ │ │ │ ├── assets │ │ │ │ ├── App.css │ │ │ │ └── index.css │ │ │ │ └── index.jsx │ │ ├── react-spa │ │ │ ├── README.md │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ ├── favicon.ico │ │ │ │ ├── index.html │ │ │ │ ├── logo192.png │ │ │ │ ├── logo512.png │ │ │ │ ├── manifest.json │ │ │ │ └── robots.txt │ │ │ └── src │ │ │ │ ├── App.css │ │ │ │ ├── App.jsx │ │ │ │ ├── App.test.js │ │ │ │ ├── index.css │ │ │ │ ├── index.jsx │ │ │ │ ├── logo.svg │ │ │ │ ├── reportWebVitals.js │ │ │ │ └── setupTests.js │ │ ├── vue-mpa │ │ │ ├── .browserslistrc │ │ │ ├── README.md │ │ │ ├── babel.config.js │ │ │ ├── package.json │ │ │ ├── public │ │ │ │ ├── favicon.ico │ │ │ │ └── index.html │ │ │ ├── src │ │ │ │ ├── assets │ │ │ │ │ └── logo.png │ │ │ │ ├── components │ │ │ │ │ └── HelloWorld.vue │ │ │ │ └── pages │ │ │ │ │ ├── index │ │ │ │ │ ├── App.vue │ │ │ │ │ ├── main.js │ │ │ │ │ ├── router │ │ │ │ │ │ └── index.js │ │ │ │ │ ├── store │ │ │ │ │ │ └── index.js │ │ │ │ │ └── views │ │ │ │ │ │ ├── About.vue │ │ │ │ │ │ └── Home.vue │ │ │ │ │ └── second │ │ │ │ │ ├── App.vue │ │ │ │ │ ├── main.js │ │ │ │ │ ├── router │ │ │ │ │ └── index.js │ │ │ │ │ ├── store │ │ │ │ │ └── index.js │ │ │ │ │ └── views │ │ │ │ │ ├── About.vue │ │ │ │ │ └── Home.vue │ │ │ ├── vite.config.js │ │ │ └── vue.config.js │ │ └── vue-spa │ │ │ ├── .browserslistrc │ │ │ ├── README.md │ │ │ ├── babel.config.js │ │ │ ├── package.json │ │ │ ├── public │ │ │ ├── favicon.ico │ │ │ └── index.html │ │ │ └── src │ │ │ ├── App.vue │ │ │ ├── assets │ │ │ └── logo.png │ │ │ ├── components │ │ │ └── HelloWorld.vue │ │ │ ├── main.js │ │ │ ├── router │ │ │ └── index.js │ │ │ ├── store │ │ │ └── index.js │ │ │ └── views │ │ │ ├── About.vue │ │ │ └── Home.vue │ └── ts │ │ ├── react-mpa │ │ └── .gitkeep │ │ ├── react-spa │ │ ├── README.md │ │ ├── package.json │ │ ├── public │ │ │ ├── favicon.ico │ │ │ ├── index.html │ │ │ ├── logo192.png │ │ │ ├── logo512.png │ │ │ ├── manifest.json │ │ │ └── robots.txt │ │ ├── src │ │ │ ├── App.css │ │ │ ├── App.tsx │ │ │ ├── index.css │ │ │ ├── index.tsx │ │ │ ├── logo.svg │ │ │ └── react-app-env.d.ts │ │ └── tsconfig.json │ │ ├── vue-mpa │ │ ├── .browserslistrc │ │ ├── .editorconfig │ │ ├── .eslintrc.js │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── public │ │ │ ├── favicon.ico │ │ │ └── index.html │ │ ├── src │ │ │ ├── assets │ │ │ │ └── logo.png │ │ │ ├── components │ │ │ │ └── HelloWorld.vue │ │ │ ├── pages │ │ │ │ ├── index │ │ │ │ │ ├── App.vue │ │ │ │ │ ├── main.ts │ │ │ │ │ ├── router │ │ │ │ │ │ └── index.ts │ │ │ │ │ ├── store │ │ │ │ │ │ └── index.ts │ │ │ │ │ └── views │ │ │ │ │ │ ├── About.vue │ │ │ │ │ │ └── Home.vue │ │ │ │ └── second │ │ │ │ │ ├── App.vue │ │ │ │ │ ├── main.ts │ │ │ │ │ ├── router │ │ │ │ │ └── index.ts │ │ │ │ │ ├── store │ │ │ │ │ └── index.ts │ │ │ │ │ └── views │ │ │ │ │ ├── About.vue │ │ │ │ │ └── Home.vue │ │ │ └── shims-vue.d.ts │ │ ├── tsconfig.json │ │ ├── vite.config.ts │ │ └── vue.config.js │ │ └── vue-spa │ │ ├── .browserslistrc │ │ ├── .editorconfig │ │ ├── .eslintrc.js │ │ ├── README.md │ │ ├── babel.config.js │ │ ├── package.json │ │ ├── public │ │ ├── favicon.ico │ │ └── index.html │ │ ├── src │ │ ├── App.vue │ │ ├── assets │ │ │ └── logo.png │ │ ├── components │ │ │ └── HelloWorld.vue │ │ ├── main.ts │ │ ├── router │ │ │ └── index.ts │ │ ├── shims-vue.d.ts │ │ ├── store │ │ │ └── index.ts │ │ └── views │ │ │ ├── About.vue │ │ │ └── Home.vue │ │ └── tsconfig.json └── webpack-vite-serve │ ├── package.json │ ├── public │ └── index.html │ ├── src │ ├── bin.ts │ ├── command │ │ ├── build.ts │ │ ├── index.ts │ │ └── start.ts │ ├── config │ │ └── vite.ts │ ├── plugins │ │ ├── buildPlugin.ts │ │ ├── htmlTplPlugin.ts │ │ ├── index.ts │ │ ├── pageEntryPlugin.ts │ │ ├── userConfigPlugin.ts │ │ └── wp2vitePlugin.ts │ ├── types │ │ └── index.ts │ └── utils │ │ └── index.ts │ ├── tsconfig.json │ └── tsup.config.ts ├── pnpm-workspace.yaml └── tsconfig.json /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "es2021": true 5 | }, 6 | "extends": [ 7 | "airbnb-base", 8 | "eslint:recommended", 9 | "plugin:@typescript-eslint/recommended" 10 | ], 11 | "parser": "@typescript-eslint/parser", 12 | "parserOptions": { 13 | "ecmaVersion": 12, 14 | "parser": "@typescript-eslint/parser", 15 | "sourceType": "module", 16 | "ecmaFeatures": { 17 | "jsx": true 18 | } 19 | }, 20 | "plugins": [ 21 | "@typescript-eslint" 22 | ], 23 | "rules": { 24 | "@typescript-eslint/explicit-module-boundary-types": "off", 25 | "import/extensions": "off", 26 | "no-underscore-dangle": "off", 27 | "import/no-unresolved": "off", 28 | "no-console": "off", 29 | "prefer-rest-params": "off", 30 | "import/prefer-default-export": "off", 31 | "import/no-dynamic-require": "off", 32 | "global-require": "off", 33 | "@typescript-eslint/no-var-requires": "off", 34 | "import/no-extraneous-dependencies":"off" 35 | } 36 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | yarn.lock 4 | pnpm-lock.yaml 5 | .DS_Store 6 | 7 | # local env files 8 | .env.local 9 | .env.*.local 10 | 11 | # Log files 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | pnpm-debug.log* 16 | 17 | # Editor directories and files 18 | .idea 19 | .vscode 20 | *.suo 21 | *.ntvs* 22 | *.njsproj 23 | *.sln 24 | *.sw? -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | demos 2 | tsconfig.json 3 | .gitignore 4 | .eslintrc.json 5 | node_modules 6 | pnpm-lock.yaml 7 | tsup.config.ts -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 sugar 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # webpack-vite-serve 2 | 为webpack项目提供一键接入Vite的能力 3 | 4 | 相关文章:[webpack项目接入Vite的通用方案介绍](https://sugarat.top/technology/learn/webapck2vite.html) 5 | 6 | 包管理工具推荐使用[pnpm](https://pnpm.io/) 7 | ```sh 8 | npm i -g pnpm 9 | ``` 10 | ## Usage 11 | ### Installed 12 | ```sh 13 | npm install webpack-vite-serve -D 14 | # or 15 | yarn add webpack-vite-serve -D 16 | # or 17 | pnpm add webpack-vite-serve -D 18 | ``` 19 | 20 | ### Command Run 21 | ```sh 22 | # devServer 23 | wvs start [options] 24 | ``` 25 | 26 | ```json 27 | { 28 | "scripts": { 29 | "vite:vue": "wvs start -f vue", 30 | "vite:react": "wvs start -f react", 31 | "vite": "wvs start" 32 | } 33 | } 34 | ``` 35 | 36 | ```sh 37 | # build 38 | wvs build [options] 39 | ``` 40 | ```json 41 | { 42 | "scripts": { 43 | "build:vite": "wvs build", 44 | } 45 | } 46 | ``` 47 | ### Options 48 | * [x] -f,--framework ``:指定使用的业务框架 (`vue`,`react`) 49 | * 此选项将会自动引入框架依赖的插件,react-[@vitejs/plugin-react](https://github.com/vitejs/vite/tree/main/packages/plugin-react#readme),vu3-[@vitejs/plugin-vue](https://github.com/vitejs/vite/tree/main/packages/plugin-vue#readme),vue2-[vite-plugin-vue2](https://github.com/underfin/vite-plugin-vue2/tree/master/#readme) 50 | * 用户可以不开启此选项,自行在用户配置中加入对应的插件 51 | * [x] -s,--spa:按照单页应用目录结构处理 `src/${entryJs}` 52 | * 不指定 `-s`或`-m`,**默认按单页应用** 53 | * [x] -m,--mpa:按照多页应用目录结构处理 `src/pages/${entryName}/${entryJs}` 54 | * [x] -d,--debug `[feat]`:打印debug信息 55 | * [x] -w,--wp2vite:use [wp2vite](https://github.com/tnfe/wp2vite) 自动转换webpack文件 56 | * [ ] -c,--config: 手动指定vite配置路径 57 | * [ ] -w,--webpack: 手动指定webpack配置路径 58 | 59 | 其中`entryJs`匹配命名规则`/(index|main)\.[jt]sx?$/` 60 | ## Agreement 61 | 工程目录约定 62 | ### SPA 63 | | Pages Dir | Html Template | Entry Js | 64 | | :-------: | :-----------------: | :--------------: | 65 | | `src` | `public/index.html` | `src/${entryJs}` | 66 | 67 | ```sh 68 | * public 69 | * index.html 70 | * src 71 | * main.ts 72 | ``` 73 | ### MPA 74 | | Pages Dir | Html Template | Entry Js | 75 | | :---------: | :--------------------------------------: | :---------------------------------: | 76 | | `src/pages` | `src/pages/${pageName}/${pageName}.html` | `src/pages/${entryName}/${entryJs}` | 77 | | | `src/pages/${pageName}/index.html` | - | 78 | | | `public/index.html` | - | 79 | 80 | ```sh 81 | * public 82 | * index.html 83 | * src 84 | * pages 85 | * pageName1 86 | * main.js 87 | * pageName.html 88 | * pageName2 89 | * index.ts 90 | * index.html 91 | ``` 92 | ## Supports 93 | * [x] Vue 94 | * [x] React 95 | * [x] SPA - 单页应用 96 | * [x] MPA - 多页应用 97 | * [x] build for production - 打包`wvs build` 98 | * [x] merge userConfig - 自动合并工程根目录的`vite.config.ts`文件 99 | * [x] config transform use [wp2vite](https://github.com/tnfe/wp2vite) - webpack配置转换 !!! 存在一些小小问题,准备PR解决 100 | * [ ] export inline plugin - 对外暴露内置的插件,供单独使用,如处理`htmlTemplate`与`entryJs`的能力 101 | 102 | ## Demos 103 | * JS 104 | * [x] Vue2 SPA 105 | * [x] React SPA 106 | * [x] Vue MPA 107 | * [x] React MPA 108 | * TS 109 | * [x] Vue3 SPA 110 | * [x] React SPA 111 | * [x] Vue MPA 112 | * [ ] React MPA 113 | 114 | ### Run Examples 115 | 116 | ```sh 117 | pnpm install 118 | 119 | # 1 120 | cd examples 121 | 122 | # 2 123 | cd js 124 | 125 | # 3 126 | cd react-mpa 127 | 128 | # 4 129 | # run webpack devServer 130 | npm run dev 131 | # 5 132 | # run vite devServer 133 | npm run dev:vite 134 | ``` 135 | 136 | ## Local 137 | ### Dev 138 | 使用pnpm 139 | ```sh 140 | npm i -g pnpm 141 | ``` 142 | 143 | 安装依赖 144 | ```sh 145 | pnpm install 146 | ``` 147 | 148 | 编译 149 | ```sh 150 | pnpm dev 151 | ``` 152 | 153 | 激活指令(全局) 154 | ```sh 155 | npm link 156 | ``` 157 | 158 | 测试指令 159 | ```sh 160 | wvs hello 161 | ``` 162 | 163 | ### Build 164 | 165 | 使用pnpm 166 | ```sh 167 | npm i -g pnpm 168 | ``` 169 | 170 | 安装依赖 171 | ```sh 172 | pnpm install 173 | ``` 174 | 175 | 构建 176 | ```sh 177 | pnpm build 178 | # or 179 | pnpm dev 180 | ``` -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-vite-serve-monorepo", 3 | "private": true, 4 | "description": "为webpack项目提供一键接入Vite的能力", 5 | "devDependencies": { 6 | "@types/ejs": "^3.1.0", 7 | "@types/node": "^16.11.17", 8 | "@typescript-eslint/eslint-plugin": "^5.8.0", 9 | "@typescript-eslint/parser": "^5.8.0", 10 | "esbuild-plugin-public-directory": "^0.0.4", 11 | "eslint": "^8.5.0", 12 | "eslint-config-airbnb-base": "^14.2.1", 13 | "eslint-plugin-import": "^2.25.3", 14 | "rimraf": "^3.0.2", 15 | "tsup": "^5.11.9", 16 | "typescript": "^4.5.4" 17 | }, 18 | "scripts": { 19 | "preinstall": "npx only-allow pnpm", 20 | "lint": "eslint packages/** --fix", 21 | "build": "cd packages/webpack-vite-serve && npm run build", 22 | "dev": "cd packages/webpack-vite-serve && npm run dev", 23 | "build:example": "pnpm -r build:vite --workspace-concurrency 0" 24 | }, 25 | "repository": { 26 | "type": "git", 27 | "url": "git+https://github.com/ATQQ/webpack-vite-serve.git" 28 | }, 29 | "license": "MIT", 30 | "bugs": { 31 | "url": "https://github.com/ATQQ/webpack-vite-serve/issues" 32 | }, 33 | "homepage": "https://github.com/ATQQ/webpack-vite-serve#readme" 34 | } 35 | -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `yarn dev` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `yarn test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `yarn build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `yarn eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `yarn build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-react-mpa", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^17.0.2", 7 | "react-dom": "^17.0.2", 8 | "react-scripts": "4.0.3", 9 | "web-vitals": "^1.0.1" 10 | }, 11 | "devDependencies": { 12 | "webpack-vite-serve": "workspace:*" 13 | }, 14 | "scripts": { 15 | "dev:vite": "wvs start -f react --mpa", 16 | "build:vite": "wvs build -f react --mpa", 17 | "test": "react-scripts test", 18 | "eject": "react-scripts eject" 19 | }, 20 | "eslintConfig": { 21 | "extends": [ 22 | "react-app", 23 | "react-app/jest" 24 | ] 25 | }, 26 | "browserslist": { 27 | "production": [ 28 | ">0.2%", 29 | "not dead", 30 | "not op_mini all" 31 | ], 32 | "development": [ 33 | "last 1 chrome version", 34 | "last 1 firefox version", 35 | "last 1 safari version" 36 | ] 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/js/react-mpa/public/favicon.ico -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 25 | React App 26 | 27 | 28 | 29 | 30 |
31 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/js/react-mpa/public/logo192.png -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/js/react-mpa/public/logo512.png -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/src/pages/home/App.jsx: -------------------------------------------------------------------------------- 1 | import logo from '@/assets/logo.svg'; 2 | 3 | import './assets/App.css'; 4 | 5 | function App() { 6 | return ( 7 |
8 |
9 | logo 10 |

11 | Edit src/App.js and save to reload. 12 |

13 | 19 | Learn React 20 | 21 |
22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/src/pages/home/assets/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/src/pages/home/assets/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /packages/examples/js/react-mpa/src/pages/home/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './assets/index.css'; 4 | import App from './App'; 5 | 6 | ReactDOM.render( 7 | 8 | 9 | , 10 | document.getElementById('root') 11 | ); 12 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `yarn dev` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `yarn test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `yarn build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `yarn eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `yarn build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-react-spa", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "react": "^17.0.2", 7 | "react-dom": "^17.0.2", 8 | "react-scripts": "4.0.3", 9 | "web-vitals": "^1.0.1" 10 | }, 11 | "devDependencies": { 12 | "webpack-vite-serve": "workspace:*" 13 | }, 14 | "scripts": { 15 | "dev": "SKIP_PREFLIGHT_CHECK=true react-scripts start", 16 | "dev:vite": "wvs start -f react", 17 | "build": "react-scripts build", 18 | "build:vite": "wvs build -f react", 19 | "test": "react-scripts test", 20 | "eject": "react-scripts eject" 21 | }, 22 | "eslintConfig": { 23 | "extends": [ 24 | "react-app", 25 | "react-app/jest" 26 | ] 27 | }, 28 | "browserslist": { 29 | "production": [ 30 | ">0.2%", 31 | "not dead", 32 | "not op_mini all" 33 | ], 34 | "development": [ 35 | "last 1 chrome version", 36 | "last 1 firefox version", 37 | "last 1 safari version" 38 | ] 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/js/react-spa/public/favicon.ico -------------------------------------------------------------------------------- /packages/examples/js/react-spa/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 15 | 16 | 25 | React App 26 | 27 | 28 | 29 | 30 |
31 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/js/react-spa/public/logo192.png -------------------------------------------------------------------------------- /packages/examples/js/react-spa/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/js/react-spa/public/logo512.png -------------------------------------------------------------------------------- /packages/examples/js/react-spa/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/src/App.jsx: -------------------------------------------------------------------------------- 1 | import logo from './logo.svg'; 2 | 3 | import './App.css'; 4 | 5 | function App() { 6 | return ( 7 |
8 |
9 | logo 10 |

11 | Edit src/App.js and save to reload. 12 |

13 | 19 | Learn React 20 | 21 |
22 |
23 | ); 24 | } 25 | 26 | export default App; 27 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/src/App.test.js: -------------------------------------------------------------------------------- 1 | import { render, screen } from '@testing-library/react'; 2 | import App from './App'; 3 | 4 | test('renders learn react link', () => { 5 | render(); 6 | const linkElement = screen.getByText(/learn react/i); 7 | expect(linkElement).toBeInTheDocument(); 8 | }); 9 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/src/index.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | import reportWebVitals from './reportWebVitals'; 6 | 7 | ReactDOM.render( 8 | 9 | 10 | , 11 | document.getElementById('root') 12 | ); 13 | 14 | // If you want to start measuring performance in your app, pass a function 15 | // to log results (for example: reportWebVitals(console.log)) 16 | // or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals 17 | reportWebVitals(); 18 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/src/reportWebVitals.js: -------------------------------------------------------------------------------- 1 | const reportWebVitals = onPerfEntry => { 2 | if (onPerfEntry && onPerfEntry instanceof Function) { 3 | import('web-vitals').then(({ getCLS, getFID, getFCP, getLCP, getTTFB }) => { 4 | getCLS(onPerfEntry); 5 | getFID(onPerfEntry); 6 | getFCP(onPerfEntry); 7 | getLCP(onPerfEntry); 8 | getTTFB(onPerfEntry); 9 | }); 10 | } 11 | }; 12 | 13 | export default reportWebVitals; 14 | -------------------------------------------------------------------------------- /packages/examples/js/react-spa/src/setupTests.js: -------------------------------------------------------------------------------- 1 | // jest-dom adds custom jest matchers for asserting on DOM nodes. 2 | // allows you to do things like: 3 | // expect(element).toHaveTextContent(/react/i) 4 | // learn more: https://github.com/testing-library/jest-dom 5 | import '@testing-library/jest-dom'; 6 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/README.md: -------------------------------------------------------------------------------- 1 | # vue2-spa-js 2 | 3 | ## Project setup 4 | ``` 5 | pnpm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | pnpm run dev 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | pnpm run build 16 | ``` 17 | 18 | ### Customize configuration 19 | See [Configuration Reference](https://cli.vuejs.org/config/). 20 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-vue2-mpa", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vue-cli-service serve", 7 | "dev:vite": "wvs start -f vue --mpa", 8 | "build": "vue-cli-service build", 9 | "build:vite": "wvs build -f vue --mpa" 10 | }, 11 | "dependencies": { 12 | "core-js": "^3.6.5", 13 | "vue": "^2.6.11", 14 | "vue-router": "^3.2.0", 15 | "vuex": "^3.4.0", 16 | "webpack-vite-serve": "workspace:*" 17 | }, 18 | "devDependencies": { 19 | "@vue/cli-plugin-babel": "~4.5.0", 20 | "@vue/cli-plugin-router": "~4.5.0", 21 | "@vue/cli-plugin-vuex": "~4.5.0", 22 | "@vue/cli-service": "~4.5.0", 23 | "vue-template-compiler": "^2.6.11" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/js/vue-mpa/public/favicon.ico -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/js/vue-mpa/src/assets/logo.png -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 42 | 43 | 44 | 60 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/index/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 33 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/index/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from './store'; 5 | 6 | new Vue({ 7 | router, 8 | store, 9 | render: (h) => h(App), 10 | }).$mount('#app'); 11 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/index/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueRouter from 'vue-router'; 3 | import Home from '../views/Home.vue'; 4 | 5 | Vue.use(VueRouter); 6 | 7 | const routes = [ 8 | { 9 | path: '/index', 10 | name: 'Home', 11 | component: Home, 12 | }, 13 | { 14 | path: '/index/about', 15 | name: 'About', 16 | // route level code-splitting 17 | // this generates a separate chunk (about.[hash].js) for this route 18 | // which is lazy-loaded when the route is visited. 19 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), 20 | }, 21 | ]; 22 | 23 | const router = new VueRouter({ 24 | mode: 'history', 25 | base: process.env.BASE_URL, 26 | routes, 27 | }); 28 | 29 | export default router; 30 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/index/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | }, 9 | mutations: { 10 | }, 11 | actions: { 12 | }, 13 | modules: { 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/index/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/index/views/Home.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 18 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/second/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 33 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/second/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from './store'; 5 | 6 | Vue.config.productionTip = false; 7 | 8 | new Vue({ 9 | router, 10 | store, 11 | render: (h) => h(App), 12 | }).$mount('#app'); 13 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/second/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import VueRouter from 'vue-router'; 3 | import Home from '../views/Home.vue'; 4 | 5 | Vue.use(VueRouter); 6 | 7 | const routes = [ 8 | { 9 | path: '/second', 10 | name: 'Home', 11 | component: Home, 12 | }, 13 | { 14 | path: '/second/about', 15 | name: 'About', 16 | // route level code-splitting 17 | // this generates a separate chunk (about.[hash].js) for this route 18 | // which is lazy-loaded when the route is visited. 19 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), 20 | }, 21 | ]; 22 | 23 | const router = new VueRouter({ 24 | mode: 'history', 25 | base: process.env.BASE_URL, 26 | routes, 27 | }); 28 | 29 | export default router; 30 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/second/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Vuex from 'vuex'; 3 | 4 | Vue.use(Vuex); 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | }, 9 | mutations: { 10 | }, 11 | actions: { 12 | }, 13 | modules: { 14 | }, 15 | }); 16 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/second/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/src/pages/second/views/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/vite.config.js: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | 3 | export default defineConfig({ 4 | server: { 5 | open: '/', 6 | }, 7 | }); 8 | -------------------------------------------------------------------------------- /packages/examples/js/vue-mpa/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pages: { 3 | index: { 4 | entry: './src/pages/index/main.js', 5 | template: './public/index.html', 6 | }, 7 | second: { 8 | entry: './src/pages/second/main.js', 9 | template: './public/index.html', 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/README.md: -------------------------------------------------------------------------------- 1 | # vue2-spa-js 2 | 3 | ## Project setup 4 | ``` 5 | pnpm install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | pnpm run dev 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | pnpm run build 16 | ``` 17 | 18 | ### Customize configuration 19 | See [Configuration Reference](https://cli.vuejs.org/config/). 20 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-vue2-spa", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vue-cli-service serve", 7 | "dev:vite": "wvs start -f vue", 8 | "build": "vue-cli-service build", 9 | "build:vite": "wvs build -f vue" 10 | }, 11 | "dependencies": { 12 | "core-js": "^3.6.5", 13 | "vue": "^2.6.11", 14 | "vue-router": "^3.2.0", 15 | "vuex": "^3.4.0", 16 | "webpack-vite-serve": "workspace:*" 17 | }, 18 | "devDependencies": { 19 | "@vue/cli-plugin-babel": "~4.5.0", 20 | "@vue/cli-plugin-router": "~4.5.0", 21 | "@vue/cli-plugin-vuex": "~4.5.0", 22 | "@vue/cli-service": "~4.5.0", 23 | "vue-template-compiler": "^2.6.11" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/js/vue-spa/public/favicon.ico -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | <%= htmlWebpackPlugin.options.title %> 11 | 12 | 13 | 14 | 15 | 19 |
20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/src/App.vue: -------------------------------------------------------------------------------- 1 | 10 | 11 | 33 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/js/vue-spa/src/assets/logo.png -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 42 | 43 | 44 | 60 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from "vue"; 2 | import App from "./App.vue"; 3 | import router from "./router"; 4 | import store from "./store"; 5 | 6 | Vue.config.productionTip = false; 7 | 8 | new Vue({ 9 | router, 10 | store, 11 | render: h => h(App) 12 | }).$mount("#app"); 13 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import VueRouter from 'vue-router' 3 | import Home from '../views/Home.vue' 4 | 5 | Vue.use(VueRouter) 6 | 7 | const routes = [ 8 | { 9 | path: '/', 10 | name: 'Home', 11 | component: Home 12 | }, 13 | { 14 | path: '/about', 15 | name: 'About', 16 | // route level code-splitting 17 | // this generates a separate chunk (about.[hash].js) for this route 18 | // which is lazy-loaded when the route is visited. 19 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue') 20 | } 21 | ] 22 | 23 | const router = new VueRouter({ 24 | mode: 'history', 25 | base: process.env.BASE_URL, 26 | routes 27 | }) 28 | 29 | export default router 30 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/src/store/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Vuex from 'vuex' 3 | 4 | Vue.use(Vuex) 5 | 6 | export default new Vuex.Store({ 7 | state: { 8 | }, 9 | mutations: { 10 | }, 11 | actions: { 12 | }, 13 | modules: { 14 | } 15 | }) 16 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/examples/js/vue-spa/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /packages/examples/ts/react-mpa/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/ts/react-mpa/.gitkeep -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/README.md: -------------------------------------------------------------------------------- 1 | # Getting Started with Create React App 2 | 3 | This project was bootstrapped with [Create React App](https://github.com/facebook/create-react-app). 4 | 5 | ## Available Scripts 6 | 7 | In the project directory, you can run: 8 | 9 | ### `yarn dev` 10 | 11 | Runs the app in the development mode.\ 12 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser. 13 | 14 | The page will reload if you make edits.\ 15 | You will also see any lint errors in the console. 16 | 17 | ### `yarn test` 18 | 19 | Launches the test runner in the interactive watch mode.\ 20 | See the section about [running tests](https://facebook.github.io/create-react-app/docs/running-tests) for more information. 21 | 22 | ### `yarn build` 23 | 24 | Builds the app for production to the `build` folder.\ 25 | It correctly bundles React in production mode and optimizes the build for the best performance. 26 | 27 | The build is minified and the filenames include the hashes.\ 28 | Your app is ready to be deployed! 29 | 30 | See the section about [deployment](https://facebook.github.io/create-react-app/docs/deployment) for more information. 31 | 32 | ### `yarn eject` 33 | 34 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!** 35 | 36 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project. 37 | 38 | Instead, it will copy all the configuration files and the transitive dependencies (webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own. 39 | 40 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it. 41 | 42 | ## Learn More 43 | 44 | You can learn more in the [Create React App documentation](https://facebook.github.io/create-react-app/docs/getting-started). 45 | 46 | To learn React, check out the [React documentation](https://reactjs.org/). 47 | 48 | ### Code Splitting 49 | 50 | This section has moved here: [https://facebook.github.io/create-react-app/docs/code-splitting](https://facebook.github.io/create-react-app/docs/code-splitting) 51 | 52 | ### Analyzing the Bundle Size 53 | 54 | This section has moved here: [https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size](https://facebook.github.io/create-react-app/docs/analyzing-the-bundle-size) 55 | 56 | ### Making a Progressive Web App 57 | 58 | This section has moved here: [https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app](https://facebook.github.io/create-react-app/docs/making-a-progressive-web-app) 59 | 60 | ### Advanced Configuration 61 | 62 | This section has moved here: [https://facebook.github.io/create-react-app/docs/advanced-configuration](https://facebook.github.io/create-react-app/docs/advanced-configuration) 63 | 64 | ### Deployment 65 | 66 | This section has moved here: [https://facebook.github.io/create-react-app/docs/deployment](https://facebook.github.io/create-react-app/docs/deployment) 67 | 68 | ### `yarn build` fails to minify 69 | 70 | This section has moved here: [https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify](https://facebook.github.io/create-react-app/docs/troubleshooting#npm-run-build-fails-to-minify) 71 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-react-spa", 3 | "version": "0.1.0", 4 | "private": true, 5 | "dependencies": { 6 | "@types/node": "^16.11.6", 7 | "@types/react": "^17.0.33", 8 | "@types/react-dom": "^17.0.10", 9 | "react": "^17.0.2", 10 | "react-dom": "^17.0.2", 11 | "react-scripts": "4.0.3", 12 | "typescript": "^4.4.4", 13 | "webpack-vite-serve": "workspace:*" 14 | }, 15 | "scripts": { 16 | "dev": "SKIP_PREFLIGHT_CHECK=true react-scripts start", 17 | "dev:vite": "wvs start -f react", 18 | "build": "react-scripts build", 19 | "build:vite": "wvs build -f react", 20 | "test": "react-scripts test", 21 | "eject": "react-scripts eject" 22 | }, 23 | "eslintConfig": { 24 | "extends": [ 25 | "react-app", 26 | "react-app/jest" 27 | ] 28 | }, 29 | "browserslist": { 30 | "production": [ 31 | ">0.2%", 32 | "not dead", 33 | "not op_mini all" 34 | ], 35 | "development": [ 36 | "last 1 chrome version", 37 | "last 1 firefox version", 38 | "last 1 safari version" 39 | ] 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/ts/react-spa/public/favicon.ico -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | React App 28 | 29 | 30 | 31 |
32 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/public/logo192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/ts/react-spa/public/logo192.png -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/public/logo512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/ts/react-spa/public/logo512.png -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "React App", 3 | "name": "Create React App Sample", 4 | "icons": [ 5 | { 6 | "src": "favicon.ico", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "logo192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "logo512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/src/App.css: -------------------------------------------------------------------------------- 1 | .App { 2 | text-align: center; 3 | } 4 | 5 | .App-logo { 6 | height: 40vmin; 7 | pointer-events: none; 8 | } 9 | 10 | @media (prefers-reduced-motion: no-preference) { 11 | .App-logo { 12 | animation: App-logo-spin infinite 20s linear; 13 | } 14 | } 15 | 16 | .App-header { 17 | background-color: #282c34; 18 | min-height: 100vh; 19 | display: flex; 20 | flex-direction: column; 21 | align-items: center; 22 | justify-content: center; 23 | font-size: calc(10px + 2vmin); 24 | color: white; 25 | } 26 | 27 | .App-link { 28 | color: #61dafb; 29 | } 30 | 31 | @keyframes App-logo-spin { 32 | from { 33 | transform: rotate(0deg); 34 | } 35 | to { 36 | transform: rotate(360deg); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/src/App.tsx: -------------------------------------------------------------------------------- 1 | import logo from './logo.svg'; 2 | import './App.css'; 3 | 4 | function App() { 5 | return ( 6 |
7 |
8 | logo 9 |

10 | Edit src/App.js and save to reload. 11 |

12 | 18 | Learn React 19 | 20 |
21 |
22 | ); 23 | } 24 | 25 | export default App; 26 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/src/index.css: -------------------------------------------------------------------------------- 1 | body { 2 | margin: 0; 3 | font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', 4 | 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', 5 | sans-serif; 6 | -webkit-font-smoothing: antialiased; 7 | -moz-osx-font-smoothing: grayscale; 8 | } 9 | 10 | code { 11 | font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', 12 | monospace; 13 | } 14 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ReactDOM from 'react-dom'; 3 | import './index.css'; 4 | import App from './App'; 5 | 6 | ReactDOM.render( 7 | 8 | 9 | , 10 | document.getElementById('root') 11 | ); 12 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/src/logo.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/src/react-app-env.d.ts: -------------------------------------------------------------------------------- 1 | /// 2 | -------------------------------------------------------------------------------- /packages/examples/ts/react-spa/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "react-jsx", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "skipLibCheck": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "lib": [ 15 | "esnext", 16 | "dom", 17 | "dom.iterable" 18 | ], 19 | "allowJs": true, 20 | "forceConsistentCasingInFileNames": true, 21 | "noFallthroughCasesInSwitch": true, 22 | "resolveJsonModule": true, 23 | "isolatedModules": true, 24 | "noEmit": true 25 | }, 26 | "include": [ 27 | "src" 28 | ], 29 | "exclude": [ 30 | "node_modules" 31 | ] 32 | } 33 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | end_of_line = lf 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true 7 | max_line_length = 100 8 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: [ 7 | 'plugin:vue/vue3-essential', 8 | '@vue/airbnb', 9 | '@vue/typescript/recommended', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 2020, 13 | }, 14 | rules: { 15 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/README.md: -------------------------------------------------------------------------------- 1 | # vue-spa-ts 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn dev 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-vue-mpa", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vue-cli-service serve", 7 | "dev:vite": "wvs start -f vue --mpa", 8 | "build": "vue-cli-service build", 9 | "build:vite": "wvs build -f vue --mpa", 10 | "lint": "vue-cli-service lint" 11 | }, 12 | "dependencies": { 13 | "core-js": "^3.6.5", 14 | "vue": "^3.2.20", 15 | "vue-router": "^4.0.0-0", 16 | "vuex": "^4.0.0-0" 17 | }, 18 | "devDependencies": { 19 | "@typescript-eslint/eslint-plugin": "^4.18.0", 20 | "@typescript-eslint/parser": "^4.18.0", 21 | "@vue/cli-plugin-babel": "~4.5.0", 22 | "@vue/cli-plugin-eslint": "~4.5.0", 23 | "@vue/cli-plugin-router": "~4.5.0", 24 | "@vue/cli-plugin-typescript": "~4.5.0", 25 | "@vue/cli-plugin-vuex": "~4.5.0", 26 | "@vue/cli-service": "~4.5.0", 27 | "@vue/compiler-sfc": "^3.0.0", 28 | "@vue/eslint-config-airbnb": "^5.0.2", 29 | "@vue/eslint-config-typescript": "^7.0.0", 30 | "eslint": "^6.7.2", 31 | "eslint-plugin-import": "^2.20.2", 32 | "eslint-plugin-vue": "^7.0.0", 33 | "typescript": "~4.1.5", 34 | "webpack-vite-serve": "workspace:*" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/ts/vue-mpa/public/favicon.ico -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | <%= htmlWebpackPlugin.options.title %> 12 | 13 | 14 | 15 | 16 | 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/ts/vue-mpa/src/assets/logo.png -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 46 | 47 | 48 | 64 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/index/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 32 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/index/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from './store'; 5 | 6 | createApp(App).use(store).use(router).mount('#app'); 7 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/index/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; 2 | import Home from '../views/Home.vue'; 3 | 4 | const routes: Array = [ 5 | { 6 | path: '/index', 7 | name: 'Home', 8 | component: Home, 9 | }, 10 | { 11 | path: '/index/about', 12 | name: 'About', 13 | // route level code-splitting 14 | // this generates a separate chunk (about.[hash].js) for this route 15 | // which is lazy-loaded when the route is visited. 16 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), 17 | }, 18 | ]; 19 | 20 | const router = createRouter({ 21 | history: createWebHistory(process.env.BASE_URL), 22 | routes, 23 | }); 24 | 25 | export default router; 26 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/index/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'vuex'; 2 | 3 | export default createStore({ 4 | state: { 5 | }, 6 | mutations: { 7 | }, 8 | actions: { 9 | }, 10 | modules: { 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/index/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/index/views/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/second/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 32 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/second/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from './store'; 5 | 6 | createApp(App).use(store).use(router).mount('#app'); 7 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/second/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; 2 | import Home from '../views/Home.vue'; 3 | 4 | const routes: Array = [ 5 | { 6 | path: '/second', 7 | name: 'Home', 8 | component: Home, 9 | }, 10 | { 11 | path: '/second/about', 12 | name: 'About', 13 | // route level code-splitting 14 | // this generates a separate chunk (about.[hash].js) for this route 15 | // which is lazy-loaded when the route is visited. 16 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), 17 | }, 18 | ]; 19 | 20 | const router = createRouter({ 21 | history: createWebHistory(process.env.BASE_URL), 22 | routes, 23 | }); 24 | 25 | export default router; 26 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/second/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'vuex'; 2 | 3 | export default createStore({ 4 | state: { 5 | }, 6 | mutations: { 7 | }, 8 | actions: { 9 | }, 10 | modules: { 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/second/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/pages/second/views/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module '*.vue' { 3 | import type { DefineComponent } from 'vue' 4 | const component: DefineComponent<{}, {}, any> 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "skipLibCheck": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": [ 15 | "webpack-env" 16 | ], 17 | "paths": { 18 | "@/*": [ 19 | "src/*" 20 | ] 21 | }, 22 | "lib": [ 23 | "esnext", 24 | "dom", 25 | "dom.iterable", 26 | "scripthost" 27 | ] 28 | }, 29 | "include": [ 30 | "src/**/*.ts", 31 | "src/**/*.tsx", 32 | "src/**/*.vue", 33 | "tests/**/*.ts", 34 | "tests/**/*.tsx" 35 | ], 36 | "exclude": [ 37 | "node_modules" 38 | ] 39 | } -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | 3 | export default defineConfig({ 4 | server: { 5 | open: '/index', 6 | }, 7 | plugins: [ 8 | { 9 | name: 'antd-css', 10 | apply: 'serve', 11 | transformIndexHtml(html) { 12 | // data可以传入模板中包含的一些变量 13 | return html.replace( 14 | '', 15 | ` 16 | `, 17 | ); 18 | }, 19 | }, 20 | ], 21 | }); 22 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-mpa/vue.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | pages: { 3 | index: { 4 | entry: './src/pages/index/main.ts', 5 | template: './public/index.html', 6 | }, 7 | second: { 8 | entry: './src/pages/second/main.ts', 9 | template: './public/index.html', 10 | }, 11 | }, 12 | }; 13 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not dead 4 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/.editorconfig: -------------------------------------------------------------------------------- 1 | [*.{js,jsx,ts,tsx,vue}] 2 | indent_style = space 3 | indent_size = 2 4 | end_of_line = lf 5 | trim_trailing_whitespace = true 6 | insert_final_newline = true 7 | max_line_length = 100 8 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true, 5 | }, 6 | extends: [ 7 | 'plugin:vue/vue3-essential', 8 | '@vue/airbnb', 9 | '@vue/typescript/recommended', 10 | ], 11 | parserOptions: { 12 | ecmaVersion: 2020, 13 | }, 14 | rules: { 15 | 'no-console': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 16 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'warn' : 'off', 17 | }, 18 | }; 19 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/README.md: -------------------------------------------------------------------------------- 1 | # vue-spa-ts 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn dev 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset', 4 | ], 5 | }; 6 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ts-vue-spa", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "dev": "vue-cli-service serve", 7 | "dev:vite": "wvs start -f vue", 8 | "build": "vue-cli-service build", 9 | "build:vite": "wvs build -f vue", 10 | "lint": "vue-cli-service lint" 11 | }, 12 | "dependencies": { 13 | "core-js": "^3.6.5", 14 | "vue": "^3.2.20", 15 | "vue-router": "^4.0.0-0", 16 | "vuex": "^4.0.0-0" 17 | }, 18 | "devDependencies": { 19 | "@typescript-eslint/eslint-plugin": "^4.18.0", 20 | "@typescript-eslint/parser": "^4.18.0", 21 | "@vue/cli-plugin-babel": "~4.5.0", 22 | "@vue/cli-plugin-eslint": "~4.5.0", 23 | "@vue/cli-plugin-router": "~4.5.0", 24 | "@vue/cli-plugin-typescript": "~4.5.0", 25 | "@vue/cli-plugin-vuex": "~4.5.0", 26 | "@vue/cli-service": "~4.5.0", 27 | "@vue/compiler-sfc": "^3.0.0", 28 | "@vue/eslint-config-airbnb": "^5.0.2", 29 | "@vue/eslint-config-typescript": "^7.0.0", 30 | "eslint": "^6.7.2", 31 | "eslint-plugin-import": "^2.20.2", 32 | "eslint-plugin-vue": "^7.0.0", 33 | "typescript": "~4.1.5", 34 | "webpack-vite-serve": "workspace:*" 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/ts/vue-spa/public/favicon.ico -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/src/App.vue: -------------------------------------------------------------------------------- 1 | 9 | 10 | 32 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ATQQ/webpack-vite-serve/f298698e973ebecb6e33ab136b06c10d4b18c1b4/packages/examples/ts/vue-spa/src/assets/logo.png -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 35 | 36 | 46 | 47 | 48 | 64 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/src/main.ts: -------------------------------------------------------------------------------- 1 | import { createApp } from 'vue'; 2 | import App from './App.vue'; 3 | import router from './router'; 4 | import store from './store'; 5 | 6 | createApp(App).use(store).use(router).mount('#app'); 7 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/src/router/index.ts: -------------------------------------------------------------------------------- 1 | import { createRouter, createWebHistory, RouteRecordRaw } from 'vue-router'; 2 | import Home from '../views/Home.vue'; 3 | 4 | const routes: Array = [ 5 | { 6 | path: '/', 7 | name: 'Home', 8 | component: Home, 9 | }, 10 | { 11 | path: '/about', 12 | name: 'About', 13 | // route level code-splitting 14 | // this generates a separate chunk (about.[hash].js) for this route 15 | // which is lazy-loaded when the route is visited. 16 | component: () => import(/* webpackChunkName: "about" */ '../views/About.vue'), 17 | }, 18 | ]; 19 | 20 | const router = createRouter({ 21 | history: createWebHistory(process.env.BASE_URL), 22 | routes, 23 | }); 24 | 25 | export default router; 26 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/src/shims-vue.d.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | declare module '*.vue' { 3 | import type { DefineComponent } from 'vue' 4 | const component: DefineComponent<{}, {}, any> 5 | export default component 6 | } 7 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/src/store/index.ts: -------------------------------------------------------------------------------- 1 | import { createStore } from 'vuex'; 2 | 3 | export default createStore({ 4 | state: { 5 | }, 6 | mutations: { 7 | }, 8 | actions: { 9 | }, 10 | modules: { 11 | }, 12 | }); 13 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/src/views/About.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 19 | -------------------------------------------------------------------------------- /packages/examples/ts/vue-spa/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "esnext", 4 | "module": "esnext", 5 | "strict": true, 6 | "jsx": "preserve", 7 | "importHelpers": true, 8 | "moduleResolution": "node", 9 | "skipLibCheck": true, 10 | "esModuleInterop": true, 11 | "allowSyntheticDefaultImports": true, 12 | "sourceMap": true, 13 | "baseUrl": ".", 14 | "types": [ 15 | "webpack-env" 16 | ], 17 | "paths": { 18 | "@/*": [ 19 | "src/*" 20 | ] 21 | }, 22 | "lib": [ 23 | "esnext", 24 | "dom", 25 | "dom.iterable", 26 | "scripthost" 27 | ] 28 | }, 29 | "include": [ 30 | "src/**/*.ts", 31 | "src/**/*.tsx", 32 | "src/**/*.vue", 33 | "tests/**/*.ts", 34 | "tests/**/*.tsx" 35 | ], 36 | "exclude": [ 37 | "node_modules" 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "webpack-vite-serve", 3 | "version": "0.1.2", 4 | "description": "为webpack项目提供一键接入Vite的能力", 5 | "main": "dist/index.js", 6 | "bin": { 7 | "wvs": "dist/bin.js" 8 | }, 9 | "files": [ 10 | "dist" 11 | ], 12 | "scripts": { 13 | "dev": "tsup --watch", 14 | "build": "rimraf dist && tsup --minify", 15 | "prepublish": "npm run build", 16 | "up:major": "npm version major", 17 | "up:minor": "npm version minor", 18 | "up:patch": "npm version patch", 19 | "up:beta": "npm version prerelease --preid=beta", 20 | "publish:beta": "npm publish --tag beta" 21 | }, 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/ATQQ/webpack-vite-serve.git" 25 | }, 26 | "keywords": [ 27 | "vite", 28 | "webpack", 29 | "vue", 30 | "react", 31 | "vite-plugin" 32 | ], 33 | "author": "sugar", 34 | "license": "MIT" 35 | , 36 | "bugs": { 37 | "url": "https://github.com/ATQQ/webpack-vite-serve/issues" 38 | }, 39 | "homepage": "https://github.com/ATQQ/webpack-vite-serve#readme", 40 | "dependencies": { 41 | "@vitejs/plugin-react": "^1.1.0", 42 | "@vitejs/plugin-vue": "^1.10.1", 43 | "chalk": "^4.1.2", 44 | "commander": "^8.3.0", 45 | "cross-spawn": "^7.0.3", 46 | "ejs": "^3.1.6", 47 | "inquirer": "^8.2.0", 48 | "vite": "^2.6.14", 49 | "vite-plugin-env-compatible": "^1.1.1", 50 | "vite-plugin-vue2": "^1.9.0", 51 | "wp2vite": "^2.0.8" 52 | }, 53 | "devDependencies": {} 54 | } 55 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | App(wvs) 9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/bin.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | import chalk from 'chalk'; 3 | import { Command } from 'commander'; 4 | import { buildCommand, startCommand } from './command'; 5 | // eslint-disable-next-line @typescript-eslint/no-var-requires 6 | const pkg = require('../package.json'); 7 | 8 | const program = new Command(); 9 | 10 | // 设置版号 11 | program.version(pkg.version); 12 | 13 | program.command('start') 14 | .alias('s') 15 | .option('-c, --config ', 'set webpack config path') 16 | .option('-s, --spa', 'as spa application') 17 | .option('-m, --mpa', 'as mpa application') 18 | .option('-d, --debug [feat]', 'show debug logs') 19 | .option('-w, --wp2vite', 'use wp2vite transform webpack config') 20 | .option('-f, --framework ', 'set project type [vue/react]') 21 | .action(startCommand); 22 | 23 | program.command('build') 24 | .alias('s') 25 | .option('-c, --config ', 'set webpack config path') 26 | .option('-s, --spa', 'as spa application') 27 | .option('-m, --mpa', 'as mpa application') 28 | .option('-d, --debug [feat]', 'show debug logs') 29 | .option('-w, --wp2vite', 'use wp2vite transform webpack config') 30 | .option('-f, --framework ', 'set project type [vue/react]') 31 | .action(buildCommand); 32 | 33 | program.command('hello') 34 | .action(() => { 35 | console.log(chalk.blue('--------------------------')); 36 | console.log(chalk.green(`${chalk.blue('-')} 💐 hello ${chalk.yellow('wvs')} 💐 ${chalk.blue('-')}`)); 37 | console.log(chalk.blue('--------------------------')); 38 | }); 39 | 40 | program.parse(process.argv); 41 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/command/build.ts: -------------------------------------------------------------------------------- 1 | import spawn from 'cross-spawn'; 2 | import path from 'path'; 3 | import { CommandOptions } from '../types'; 4 | 5 | export default function buildCommand(options:CommandOptions) { 6 | const { 7 | framework = '', mpa, spa, debug, wp2vite, 8 | } = options; 9 | 10 | // 不支持两个参数同时设定 11 | if (mpa && spa) { 12 | throw new Error('only support set mpa or spa'); 13 | } 14 | process.env.SPA = spa ? 'true' : ''; 15 | process.env.MPA = mpa ? 'true' : ''; 16 | process.env.WP2VITE = wp2vite ? 'true' : ''; 17 | 18 | process.env.framework = framework.toUpperCase(); 19 | 20 | const configPath = path.resolve(__dirname, './config/vite.js'); 21 | const params = ['build', '--config', configPath]; 22 | 23 | if (debug) { 24 | // 标志debug 25 | process.env.DEBUG = 'true'; 26 | 27 | // vite debug 28 | params.push('--debug'); 29 | if (typeof debug === 'string') { 30 | params.push(debug); 31 | } 32 | } 33 | process.env.mode = 'production'; 34 | process.env.command = 'build'; 35 | const viteService = spawn('vite', params, { 36 | cwd: process.cwd(), 37 | stdio: 'inherit', 38 | }); 39 | 40 | viteService.on('close', (code) => { 41 | process.exit(code); 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/command/index.ts: -------------------------------------------------------------------------------- 1 | export { default as startCommand } from './start'; 2 | export { default as buildCommand } from './build'; 3 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/command/start.ts: -------------------------------------------------------------------------------- 1 | import spawn from 'cross-spawn'; 2 | import path from 'path'; 3 | import { CommandOptions } from '../types'; 4 | 5 | export default function startCommand(options:CommandOptions) { 6 | const { 7 | framework = '', mpa, spa, debug, wp2vite, 8 | } = options; 9 | 10 | // 不支持两个参数同时设定 11 | if (mpa && spa) { 12 | throw new Error('only support set mpa or spa'); 13 | } 14 | process.env.SPA = spa ? 'true' : ''; 15 | process.env.MPA = mpa ? 'true' : ''; 16 | process.env.WP2VITE = wp2vite ? 'true' : ''; 17 | 18 | process.env.framework = framework.toUpperCase(); 19 | 20 | const configPath = path.resolve(__dirname, './config/vite.js'); 21 | const params = ['--config', configPath]; 22 | 23 | if (debug) { 24 | // 标志debug 25 | process.env.DEBUG = 'true'; 26 | 27 | // vite debug 28 | params.push('--debug'); 29 | if (typeof debug === 'string') { 30 | params.push(debug); 31 | } 32 | } 33 | process.env.mode = 'development'; 34 | process.env.command = 'serve'; 35 | const viteService = spawn('vite', params, { 36 | cwd: process.cwd(), 37 | stdio: 'inherit', 38 | }); 39 | 40 | viteService.on('close', (code) => { 41 | process.exit(code); 42 | }); 43 | } 44 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/config/vite.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable @typescript-eslint/no-var-requires */ 2 | /* eslint-disable global-require */ 3 | import { 4 | defineConfig, searchForWorkspaceRoot, mergeConfig, Plugin, UserConfig, 5 | } from 'vite'; 6 | import env from 'vite-plugin-env-compatible'; 7 | import { 8 | htmlTemplatePlugin, pageEntryPlugin, buildPlugin, userConfigPlugin, wp2vitePlugin, 9 | } from '../plugins/index'; 10 | import { getCWD, moduleIsExist, resolved } from '../utils'; 11 | 12 | const extraPlugins = []; 13 | 14 | // 修改用户配置的plugin 15 | const configPlugins = [userConfigPlugin()]; 16 | 17 | if (process.env.framework === 'VUE' && moduleIsExist('vue')) { 18 | const { version } = require('vue/package.json'); 19 | // TODO;根据版本,做判断,jsx支持 20 | if (version.startsWith('3')) { 21 | const vue = require('@vitejs/plugin-vue'); 22 | extraPlugins.push(vue()); 23 | } else { 24 | const { createVuePlugin } = require('vite-plugin-vue2'); 25 | extraPlugins.push(createVuePlugin()); 26 | } 27 | } 28 | if (process.env.framework === 'REACT') { 29 | const react = require('@vitejs/plugin-react'); 30 | extraPlugins.push(...[react()]); 31 | } 32 | 33 | // 使用wp2vite自动转换webpack配置 34 | if (process.env.WP2VITE) { 35 | configPlugins.push(wp2vitePlugin()); 36 | } 37 | 38 | // 内置依赖预构建 39 | const optimizeDepsInclude = [ 40 | 'vue', 'vue-router', 'vuex', 'react', 'react-dom', 'react-router', 41 | ].filter((d) => moduleIsExist(d)); 42 | 43 | module.exports = defineConfig(async () => { 44 | let config: UserConfig = { 45 | plugins: [ 46 | // // 合并用户配置 47 | // userConfigPlugin(), 48 | env({ 49 | prefix: '', 50 | }), 51 | htmlTemplatePlugin(), 52 | pageEntryPlugin(), 53 | buildPlugin(), 54 | ...extraPlugins, 55 | ], 56 | server: { 57 | host: '0.0.0.0', 58 | fs: { 59 | allow: [searchForWorkspaceRoot(getCWD())], 60 | }, 61 | }, 62 | optimizeDeps: { 63 | include: optimizeDepsInclude, 64 | }, 65 | resolve: { 66 | alias: { 67 | // 兜底 68 | '@/': `${resolved('src/')}`, 69 | }, 70 | }, 71 | css: { 72 | preprocessorOptions: { 73 | less: { 74 | // 支持内联 JavaScript 75 | javascriptEnabled: true, 76 | }, 77 | }, 78 | }, 79 | }; 80 | // eslint-disable-next-line no-restricted-syntax 81 | for (const p of configPlugins) { 82 | const { config: configHook } = p as Plugin; 83 | if (configHook) { 84 | const configEnv = { 85 | command: process.env.command as 'build' | 'serve', 86 | mode: process.env.mode, 87 | }; 88 | // eslint-disable-next-line no-await-in-loop 89 | const res = await configHook(config, configEnv); 90 | if (res) { 91 | config = mergeConfig(config, res); 92 | } 93 | } 94 | } 95 | return config; 96 | }); 97 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/plugins/buildPlugin.ts: -------------------------------------------------------------------------------- 1 | import { 2 | rmdirSync, writeFileSync, readFileSync, 3 | } from 'fs'; 4 | import path from 'path'; 5 | import type { PluginOption, ResolvedConfig } from 'vite'; 6 | import { 7 | getEntryFullPath, getEntryHtml, getMpaPageEntry, isMPA, resolved, 8 | } from '../utils'; 9 | 10 | const tempHtmlName = '.wvs_temp_index.html'; 11 | export default function BuildPlugin(): PluginOption { 12 | const entry = []; 13 | 14 | // 构建开始前配置entry 15 | if (isMPA()) { 16 | entry.push(...getMpaPageEntry()); 17 | } else { 18 | // 单页应用 19 | entry.push({ 20 | entryName: 'index', 21 | entryHtml: 'public/index.html', 22 | entryJs: getEntryFullPath('src'), 23 | }); 24 | } 25 | const htmlContentMap = new Map(); 26 | let userConfig: ResolvedConfig = null; 27 | return { 28 | name: 'wvs-build', 29 | apply: 'build', 30 | configResolved(cfg) { 31 | userConfig = cfg; 32 | }, 33 | config() { 34 | const input = entry.reduce((pre, v) => { 35 | const { entryName, entryHtml, entryJs } = v; 36 | const html = getEntryHtml(entryHtml, path.join('/', entryJs)); 37 | const htmlEntryPath = resolved(path.parse(entryJs).dir, tempHtmlName); 38 | // 存储内容 39 | htmlContentMap.set(htmlEntryPath, html); 40 | // eslint-disable-next-line no-param-reassign 41 | pre[entryName] = htmlEntryPath; 42 | return pre; 43 | }, {}); 44 | return { 45 | build: { 46 | rollupOptions: { 47 | input, 48 | }, 49 | }, 50 | }; 51 | }, 52 | load(id) { 53 | if (id.endsWith('.html')) { 54 | return htmlContentMap.get(id); 55 | } 56 | return null; 57 | }, 58 | resolveId(id) { 59 | if (id.endsWith('.html')) { 60 | return id; 61 | } 62 | return null; 63 | }, 64 | // 构建完成后 65 | closeBundle() { 66 | const { outDir } = userConfig.build; 67 | // 目录调整 68 | entry.forEach((e) => { 69 | const { entryName, entryJs } = e; 70 | const outputHtmlPath = path.join(outDir, path.parse(entryJs).dir, tempHtmlName) 71 | writeFileSync(path.join(outDir, `${entryName}.html`), readFileSync(outputHtmlPath)); 72 | }); 73 | // 移除临时资源 74 | rmdirSync(path.join(outDir, 'src'), { recursive: true }); 75 | }, 76 | }; 77 | } 78 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/plugins/htmlTplPlugin.ts: -------------------------------------------------------------------------------- 1 | import type { PluginOption } from 'vite'; 2 | import { 3 | getPageName, parseURL, transformTpl, loadPageHtml, getMpaPageEntry, isMPA, 4 | } from '../utils'; 5 | 6 | export default function HtmlTemplatePlugin(): PluginOption { 7 | let pages = []; 8 | if (isMPA()) { 9 | pages = getMpaPageEntry(); 10 | } 11 | return { 12 | name: 'wvs-html-tpl', 13 | apply: 'serve', 14 | configureServer(server) { 15 | const { middlewares: app } = server; 16 | app.use(async (req, res, next) => { 17 | const htmlAccepts = ['text/html', 'application/xhtml+xml']; 18 | const isHtml = !!htmlAccepts.find((a) => req.headers?.accept?.includes(a)); 19 | const { pathname } = parseURL(req.url); 20 | // 多页应用 自动跳转 302 重定向 21 | if (isMPA() && isHtml && pathname === '/' && pages[0]) { 22 | res.statusCode = 302; 23 | res.setHeader('Location', `/${pages[0]?.entryName || ''}`); 24 | res.end(); 25 | return; 26 | } 27 | if (isHtml) { 28 | const pageName = getPageName(req.url); 29 | const originHtml = loadPageHtml(pageName); 30 | const html = await server.transformIndexHtml(req.url, originHtml, req.originalUrl); 31 | res.end(html); 32 | return; 33 | } 34 | next(); 35 | }); 36 | }, 37 | transformIndexHtml(html) { 38 | // data可以传入模板中包含的一些变量 39 | return transformTpl(html); 40 | }, 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/plugins/index.ts: -------------------------------------------------------------------------------- 1 | export { default as htmlTemplatePlugin } from './htmlTplPlugin'; 2 | export { default as pageEntryPlugin } from './pageEntryPlugin'; 3 | export { default as buildPlugin } from './buildPlugin'; 4 | export { default as userConfigPlugin } from './userConfigPlugin'; 5 | export { default as wp2vitePlugin } from './wp2vitePlugin'; 6 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/plugins/pageEntryPlugin.ts: -------------------------------------------------------------------------------- 1 | import type { PluginOption } from 'vite'; 2 | import path from 'path'; 3 | import { getEntryFullPath, getPageName, isMPA } from '../utils'; 4 | 5 | function getPageEntry(reqUrl) { 6 | if (isMPA()) { 7 | const pageName = getPageName(reqUrl); 8 | return !!pageName && getEntryFullPath(`src/pages/${pageName}`); 9 | } 10 | // 其它场景跟MPA处理类似 11 | 12 | // 默认SPA 13 | const SPABase = 'src'; 14 | return getEntryFullPath(SPABase); 15 | } 16 | 17 | export default function pageEntryPlugin(): PluginOption { 18 | return { 19 | name: 'wvs-page-entry', 20 | apply: 'serve', 21 | transformIndexHtml(html, ctx) { 22 | const entry = getPageEntry(ctx.originalUrl); 23 | if (!entry) { 24 | return html; 25 | } 26 | // 添加 / ,避免非一级路由查找文件错误 27 | // case场景:/index/second => index/src/main 28 | // right:/index/second => src/main 29 | return html.replace('', ` 30 | 31 | `); 32 | }, 33 | }; 34 | } 35 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/plugins/userConfigPlugin.ts: -------------------------------------------------------------------------------- 1 | import type { PluginOption } from 'vite'; 2 | import { getUserConfig } from '../utils'; 3 | 4 | export default function UserConfigPlugin(): PluginOption { 5 | return { 6 | name: 'wvs-config', 7 | async config(cfg, env) { 8 | const userConfig = await getUserConfig(env); 9 | return { 10 | ...userConfig?.config, 11 | }; 12 | }, 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/plugins/wp2vitePlugin.ts: -------------------------------------------------------------------------------- 1 | import { 2 | existsSync, readFileSync, unlinkSync, writeFileSync, 3 | } from 'fs'; 4 | import type { PluginOption } from 'vite'; 5 | import wp2vite from 'wp2vite'; 6 | import { getCWD, getUserConfig, resolved } from '../utils'; 7 | 8 | export default function wp2vitePlugin(): PluginOption { 9 | return { 10 | name: 'wvs-wp2vite', 11 | enforce: 'pre', 12 | async config(_, env) { 13 | const cfgFile = resolved('vite.config.js'); 14 | const tplFile = resolved('index.html'); 15 | const contentMap = new Map([[cfgFile, ''], [tplFile, '']]); 16 | const files = [cfgFile, tplFile]; 17 | 18 | console.time('wp2vite'); 19 | // 判断是否存在vite.config.js 、index.html 20 | // 避免 wp2vite 覆盖 21 | files.forEach((f) => { 22 | if (existsSync(f)) { 23 | contentMap.set(f, readFileSync(f, { encoding: 'utf-8' })); 24 | } 25 | }); 26 | 27 | // 转换出配置文件vite.config.js 28 | await wp2vite.start(getCWD(), { 29 | force: false, 30 | // 统一开启debug 31 | debug: !!process.env.DEBUG, 32 | }); 33 | 34 | // TODO:提PR优化 35 | // 转换耗时计算 36 | console.timeEnd('wp2vite'); 37 | 38 | // 获取wp2vite转换出的配置 39 | const cfg = await getUserConfig(env, 'js'); 40 | 41 | contentMap.forEach((v, k) => { 42 | if (v) { 43 | // 如果修改了内容,还原内容 44 | writeFileSync(k, v); 45 | } else { 46 | // 移除创建的文件 47 | unlinkSync(k); 48 | } 49 | }); 50 | 51 | if (cfg.config) { 52 | const { config } = cfg || {}; 53 | // 留下需要的配置 54 | return { 55 | resolve: config?.resolve, 56 | server: config?.server, 57 | css: config?.css, 58 | }; 59 | } 60 | 61 | return null; 62 | }, 63 | }; 64 | } 65 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/types/index.ts: -------------------------------------------------------------------------------- 1 | export interface CommandOptions{ 2 | config?:string 3 | spa?:boolean 4 | mpa?:boolean 5 | debug?:string|boolean 6 | wp2vite?:boolean 7 | framework?:string 8 | } 9 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/src/utils/index.ts: -------------------------------------------------------------------------------- 1 | /* eslint-disable import/no-dynamic-require */ 2 | /* eslint-disable global-require */ 3 | import { URL } from 'url'; 4 | import ejs from 'ejs'; 5 | import { existsSync, readdirSync, readFileSync } from 'fs'; 6 | import path from 'path'; 7 | import { loadConfigFromFile, ConfigEnv } from 'vite'; 8 | 9 | export function getCWD() { 10 | return process.cwd(); 11 | } 12 | 13 | export function parseURL(url:string) { 14 | return new URL(url, 'http://localhost'); 15 | } 16 | 17 | /** 18 | * ejs渲染 19 | */ 20 | export function transformEjsTpl(html:string, data = {}, ops = {}) { 21 | return ejs.render(html, data, ops); 22 | } 23 | 24 | export function moduleIsExist(name) { 25 | try { 26 | return !!require(name); 27 | } catch { 28 | return false; 29 | } 30 | } 31 | 32 | /** 33 | * 判断是否单页应用 34 | */ 35 | export function isSPA() { 36 | return process.env.SPA || false; 37 | } 38 | 39 | /** 40 | * 判断是否单页应用 41 | */ 42 | export function isMPA() { 43 | return !!process.env.MPA || false; 44 | } 45 | 46 | /** 47 | * 根据资源路径,动态获取pageName 48 | * @param reqUrl 资源路径 49 | * @@param cfg webpack的配置 50 | */ 51 | export function getPageName(reqUrl:string, cfg?:any) { 52 | // TODO:兼容webpack配置 historyRewrites 53 | const { pathname } = new URL(reqUrl, 'http://localhost'); 54 | const paths = pathname.split('/').filter((v) => !!v); 55 | const entryName = paths.find((p) => existsSync(path.join(getCWD(), 'src/pages', p))); 56 | return entryName || ''; 57 | } 58 | 59 | export const resolved = (...p) => path.join(getCWD(), ...p); 60 | 61 | export function getEntryFullPath(dirPath) { 62 | if (!existsSync(resolved(dirPath))) { 63 | return false; 64 | } 65 | // main|index.js|ts|jsx|tsx 66 | const entryName = /(index|main)\.[jt]sx?$/; 67 | const entryNames = readdirSync(resolved(dirPath), { withFileTypes: true }) 68 | .filter((v) => { 69 | entryName.lastIndex = 0; 70 | return v.isFile() && entryName.test(v.name); 71 | }); 72 | return entryNames.length > 0 ? path.join(dirPath, entryNames[0].name) : false; 73 | } 74 | 75 | /** 76 | * 初始化模板内容(替换 <%varName%> 一些内容) 77 | */ 78 | export function transformTpl(tplStr:string, data = {}, ops?:{ 79 | backup?:string 80 | matches?:RegExp[] 81 | }) { 82 | // TODO:可以再此处获取webpack配置,做自动转换 83 | // eslint-disable-next-line no-param-reassign 84 | data = { 85 | PUBLIC_URL: '.', 86 | BASE_URL: './', 87 | htmlWebpackPlugin: { 88 | options: { 89 | title: 'App', 90 | }, 91 | }, 92 | ...data, 93 | }; 94 | const { backup = '', matches = [] } = ops || {}; 95 | // match %Name% <%Name%> 96 | return [/?/g].concat(matches).reduce((tpl, r) => tpl.replace(r, (_, $1) => { 97 | const keys = $1.trim().split('.'); 98 | const v = keys.reduce((pre, k) => (pre instanceof Object ? pre[k] : pre), data); 99 | return (v === null || v === undefined) ? backup : v; 100 | }), tplStr); 101 | } 102 | 103 | /** 104 | * 获取构建入口文件的路径 105 | * @param tplPath 模板文件路径 106 | * @param entry 入口JS文件路径 107 | * @param data 模板中的参数 108 | */ 109 | export function getEntryHtml(tplPath:string, entry:string, data?:any) { 110 | const originHtml = readFileSync(tplPath, { encoding: 'utf-8' }); 111 | const initHtml = transformTpl(originHtml, data); 112 | const entryHtml = initHtml.replace('', ` 113 | 114 | `); 115 | return entryHtml; 116 | } 117 | 118 | /** 119 | * 获取多页应用的构建配置 120 | */ 121 | export function getMpaPageEntry(baseDir = 'src/pages') { 122 | // 获取所有的EntryName 123 | const entryNameList = readdirSync(resolved(baseDir), { withFileTypes: true }) 124 | .filter((v) => v.isDirectory()) 125 | .map((v) => v.name); 126 | 127 | return entryNameList 128 | .map((entryName) => ({ entryName, entryHtml: '', entryJs: getEntryFullPath(path.join(baseDir, entryName)) })) 129 | .filter((v) => !!v.entryJs) 130 | .map((v) => { 131 | const { entryName } = v; 132 | const entryHtml = [ 133 | // src/pages/${entryName}/${entryName}.html 134 | resolved(`src/pages/${entryName}/${entryName}.html`), 135 | // src/pages/${entryName}/index.html 136 | resolved(`src/pages/${entryName}/index.html`), 137 | // public/${entryName}.html 138 | resolved(`public/${entryName}.html`), 139 | // 应用兜底 140 | resolved('public/index.html'), 141 | // CLI兜底页面 142 | path.resolve(__dirname, '../index.html'), 143 | ].find((html) => existsSync(html)); 144 | return { 145 | ...v, 146 | entryHtml, 147 | }; 148 | }); 149 | } 150 | 151 | export function getUserConfig(configEnv:ConfigEnv, suffix = '') { 152 | const configName = 'vite.config'; 153 | const _suffix = ['ts', 'js', 'mjs', 'cjs']; 154 | if (suffix) { 155 | _suffix.unshift(suffix); 156 | } 157 | const configFile = _suffix.map((s) => `${configName}.${s}`).find((s) => existsSync(s)); 158 | return loadConfigFromFile(configEnv, configFile); 159 | } 160 | 161 | /** 162 | * 获取原始模板 163 | */ 164 | export function loadPageHtml(pageName:string) { 165 | // 兜底页面 166 | const pages = [path.resolve(__dirname, '../index.html')]; 167 | 168 | // 单页/多页默认 public/index.html 169 | pages.unshift(resolved('public/index.html')); 170 | 171 | // 多页应用可以根据请求的 路径 作进一步的判断 172 | if (isMPA()) { 173 | // src/pages/${entryName}/${entryName}.html 174 | // src/pages/${entryName}/index.html 175 | // public/${entryName}.html 176 | pages.unshift(resolved(`public/${pageName}.html`)); 177 | pages.unshift(resolved(`src/pages/${pageName}/index.html`)); 178 | pages.unshift(resolved(`src/pages/${pageName}/${pageName}.html`)); 179 | } 180 | // TODO:根据框架的配置寻找 181 | 182 | const page = pages.find((v) => existsSync(v)); 183 | return readFileSync(page, { encoding: 'utf-8' }); 184 | } 185 | -------------------------------------------------------------------------------- /packages/webpack-vite-serve/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../../tsconfig.json", 3 | "include": [ 4 | "./src" 5 | ], 6 | } -------------------------------------------------------------------------------- /packages/webpack-vite-serve/tsup.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'tsup'; 2 | import publicDir from 'esbuild-plugin-public-directory'; 3 | 4 | export default defineConfig({ 5 | splitting: false, 6 | sourcemap: true, 7 | clean: true, 8 | entryPoints: ['src/bin.ts', 'src/config/vite.ts'], 9 | external: [ 10 | 'vue', 11 | ], 12 | esbuildPlugins: [publicDir()], 13 | }); 14 | -------------------------------------------------------------------------------- /pnpm-workspace.yaml: -------------------------------------------------------------------------------- 1 | packages: 2 | - 'packages/*' 3 | - 'packages/examples/js/*' 4 | - 'packages/examples/ts/*' -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es2015", 4 | "moduleResolution": "node", 5 | "strict": false, 6 | "declaration": true, 7 | "noUnusedLocals": true, 8 | "esModuleInterop": true, 9 | "resolveJsonModule": true, 10 | "allowJs": true, 11 | "outDir": "dist", 12 | "module": "commonjs", 13 | "lib": [ 14 | "ESNext" 15 | ], 16 | "sourceMap": true, 17 | }, 18 | } --------------------------------------------------------------------------------