@originjs/webpack-to-vite
v1.2.0
Published
convert a webpack project to a vite project
Downloads
84
Readme
English | 简体中文
Webpack to Vite
convert a webpack project to a vite project. It has been offically included, detail
Quick Start
Use it directly with npx:
$ npx @originjs/webpack-to-vite <project path>
...or install it globally:
$ npm install @originjs/webpack-to-vite -g
$ webpack-to-vite <project path>
The converted Vite project could be found in a new directory filename-toVite
.
Note: the default conversion is vue-cli project. Pass in the
-t webpack
option to convert a webpack project.
Options
The CLI provides the following options:
$ webpack-to-vite --help
Usage: webpack-to-vite [options] [root]
Options:
-v, --version display version number
-d --rootDir <path> the directory of project to be converted
-t --projectType <type> the type of the project, use vue-cli or webpack (default: vue-cli)
-e --entry <type> entrance of the entire build process, webpack or vite will start from those
entry files to build, if no entry file is specified, src/main.ts or
src/main.js will be used as default
-c --cover transformed project files will cover the raw files
-h, --help display help for command
Awesome projects successfully converted
The following is a list of projects that successfully converted from a webpack project to a vite project using the tool
demos
vue-cli
- vue-manage-system -> vue-manage-system-vite
- newbee-mall-vue3-app -> newbee-mall-vue3-app-vite
- vue-realworld-example-app -> vue-realworld-example-app-vite
webpack
Conversion items
The following is a list of configuration items that need to convert
Legend of annotations:
| Mark | Description |
| ---- | ---- |
|✅|auto convert by webpack-to-vite
|
|⚠️|need manual convert|
|❌|not support now|
Base conversion
- ✅ B01: add necessary devDependencies and dependencies in
package.json
- necessary:
vite-plugin-env-compatible
,vite-plugin-html
,vite
, - necessary for Vue2:
vite-plugin-vue2
- necessary for Vue3:
@vue/compiler-sfc
,@vitejs/plugin-vue
,@vitejs/plugin-vue-jsx
- necessary:
- ✅ B02: add vite's entry file
index.html
to root directory- multiple entries defined by the
pages
option invue.config.js
is supported - please add entry point like
<script type="module" src="/src/main.js"></script>
. There's no need to adddev-client
entry point cause vite supports HMR by default
- multiple entries defined by the
- ✅ B03: add vite's config file
vite.config.js
to root directory - ✅ B04: import and use necessary plugins in
vite.config.js
- necessary:
vite-plugin-env-compatible
- necessary for Vue2:
vite-plugin-vue2
, we set{ jsx: true }
option to enablejsx
support by default - necessary for Vue3:
@vitejs/plugin-vue
,@vitejs/plugin-vue-jsx
- necessary:
- ✅ B05: imports that omit
.vue
extension is supported- ~~If the
resolve.extensions
is set to be['.mjs','.js','.ts','.jsx','.tsx','.json ','.vue']
, invite.config.js
, then you may encounter errors like 'Problems caused by using alisaes and omitting file suffixes at the same time'. We use a patch to fix this issue, in case of vite didn't accept relate PR~~ fixed since vite released version^2.5.0
- ~~If the
- ✅ B06:
sass
is supported- if
node-sass
is used in dependency, then we'll convert it tosass
to dependencies
- if
- ✅ B07:
postcss 8
is supported- if
postcss 8
is used, then we'll addpostcss
to dependencies
- if
- ⚠️ B08: fix issue 'No matching export for import typescript interface'
- Do not re-export typescript type or interface in vite. You can just export it in file A and import it in file B. Don't try to export it in file B again. The following error may occur if a type or a interface is re-exported:
Uncaught SyntaxError: The requested module '/src/app/reducers/state.ts' does not provide an export named 'RootState'
- Just remove all re-export types or interfaces in typescript project and modify corresponding imports
- ⚠️ B09: remove
Hot Module Replacement
(aka HMR) related code because vite supports HMR by default.- The following error may occur when project contains HMR relate code:
index.tsx:6 Uncaught ReferenceError: module is not defined at index.tsx:6
- ⚠️ B10: CSS Modules
- In vite, any CSS files ending with
.module.css
is considered a CSS modules file - That means you need to covert files with extension of
.css
to files with extension of.module.css
to implement CSS Modules
- In vite, any CSS files ending with
- ✅ B11:
html-webpack-plugin
is supported- Options will be applied to plugin
vite-plugin-html
- Variables injected to
index.html
will be transformed. for example,<%= htmlWebpackPlugin.options.title %>
-><%= title %>
- Import
createHtmlPlugin
fromhtml-webpack-plugin
and use it like this:
plugins: [ createHtmlPlugin({ inject: { data: { title: value, }, }, minify: { minifyCss: true } }) ]
- Options will be applied to plugin
- ⚠️ B12: specified Vite plugins
- You need to import specified Vite plugins based on your project, when this tool can not identify and import them.
- For example, if
windi.css
was used before, you should check if Vite has supported it, and then import related plugin (vite-plugin-windicss) manually refered to its plugin guide.
Vue-CLI conversion
Vue-CLI conversion is based on
vue.config.js
. Configurations will be transformed and written tovite.config.js
✅ V01: base public path
process.env.PUBLIC_URL
orpublicPath
orbaseUrl
->base
✅ V02: css options
css.loaderOptions
->css.preprocessorOptions
css.loaderOptions.less.lessOptions.modifyVars
->css.preprocessorOptions.less.modifyVars
- The
sass
configuration will influence bothsass
andscss
in Vue-CLI, but in vite we need to configure them respectively. So with onlycss.loaderOptions.sass
option is set in Vue-CLI, it will be converted tocss.preprocessorOptions.sass
andcss.preprocessorOptions.scss
. On the other hand, with onlycss.loaderOptions.scss
option is set in Vue-CLI, it will be converted tocss.preprocessorOptions.scss
.
✅ V03: server options
server.strictPort = false
is set by defaultprocess.env.PORT
ordevServer.port
->server.port
process.env.DEV_HOST
ordevServer.public
ordevServer.host
->server.host
, and converthttp://
orhttps://
to''
devServer.open
,devServer.https
->server.open
,server.https
- if
devServer.proxy
->server.proxy
is transformed in proxy configuration, we'll alsopathRewrite
->rewrite
✅ V04: build options
outputDir
->build.outDir
css.extract
->build.cssCodeSplit
- if
process.env.MODERN === 'true'
is set, we'll also setbuild.minify = esbuild
process.env.GENERATE_SOURCEMAP === 'true'
orvueConfig.productionSourceMap
orcss.sourceMap
->build.sourcemap
✅ V05:
resolve.alias
options- add alias options by default
resolve: { alias: [ { find: '/^~/', replacement: ''}, { find: '@', replacement: path.resolve(__dirname,'src') } ] }
- webpack alias options will be converted to match format above
✅ V06: client-side env variables
- extract variable names in jsp scriptlet tags
VUE_APP_VARIABLE
->process.env['VUE_APP_VARIABLE']
✅ V07: css automatic imports
- if 'style-resources-loader' is used to load css preprocessor resources, which is
pluginOptions['style-resources-loader']
. Configurations will be transformed and written tocss.preprocessorOptions
pluginOptions: { 'style-resources-loader': { preProcessor: 'less', patterns: [ resolve('src/styles/var.less'), resolve('src/styles/mixin.less') ] } }
->
css: { preprocessorOptions: { less: { additionalData: `@import "src/styles/var.less";@import "src/styles/mixin.less";` } } }
- if 'style-resources-loader' is used to load css preprocessor resources, which is
✅ V08: transform functional webpack config
- The
webpackConfigure
andchainWebpack
options could be defined as object or function invue.config.js
module - To avoid calling error when they were functional, we initialize config options and generate a temporary file (
vue.temp.config.js
) to reconfightml-webpack-plugin
- The
Webpack conversion
Webpack conversion is based on
webpack.config.js
orwebpack.base.js/webpack.dev.js/webpack.prod.js
orwebpack.build.js/webpack.production.js
, map configuration tovite.config.js
Note: if you are not using configuration files above, you need to convert configurations manually
- ✅ W01: build entry options
- if
entry
isstring
type:entry
->build.rollupOptions.input
- if
entry
isobject
type: the properties ofentry
will be converted set tobuild.rollupOptions.input
- if
entry
isfunction
type: execute result ofentry
will be set tobuild.rollupOptions.input
- if
- ✅ W02:
output
optionsoutput.path
->build.outDir
output.filename
->build.rollupOptions.output.entryFileNames
output.chunkFilename
->build.rollupOptions.output.chunkFileNames
- ✅ W03:
resolve.alias
options- add alias options by default
resolve: { alias: [ { find: '@', replacement: path.resolve(__dirname,'src') } ] }
- webpack alias options will also be converted to match the configuration above
- for
resolve.alias
configurations trailing with$
, we'll remove the trailing '$' and set an accurate value
- ✅ W04: server options
devServer.host
,devServer.port
,devServer.proxy
,devServer.https
,devServer.contentBase
->server.host
,server.port
,server.proxy
,server.https
,server.base
- ✅ W05: define options
new webpack.DefinePlugin()
->define
Others
- ⚠️ O01: for CommonJS syntax, e.g.
require('./')
- you can use vite plugin
@originjs/vite-plugin-commonjs
, see also here. Please note that the plugin only supports part of CommonJS syntax. That means some syntax is not supported. You need to covert them to ES Modules syntax manually - convert dynamic require(e.g.
require('@assets/images/' + options.src)
), you can refer to the following steps
- use Web API
new URL
...or use Vite's API<template> <img alt="" :src="imgSrc" /> </template> <script> export default { name: 'img', data: () => ({ imgSrc: new URL('./assets/logo.png', import.meta.url).href }) } </script>
import.meta.glob
- create a Model to save the imported modules, use async methods to dynamically import the modules and update them to the Model
// src/store/index.js import Vue from 'vue' import Vuex from 'vuex' const assets = import.meta.glob('../assets/**') Vue.use(Vuex) export default new Vuex.Store({ state: { assets: {} }, mutations: { setAssets(state, data) { state.assets = Object.assign({}, state.assets, data) } }, actions: { async getAssets({ commit }, url) { const getAsset = assets[url] if (!getAsset) { commit('setAssets', { [url]: ''}) } else { const asset = await getAsset() commit('setAssets', { [url]: asset.default }) } } } })
- use in
.vue
SFC
// img1.vue <template> <img :src="$store.state.assets['../assets/images/' + options.src]" /> </template> <script> export default { name: "img1", props: { options: Object }, watch: { 'options.src': { handler (val) { this.$store.dispatch('getAssets', `../assets/images/${val}`) }, immediate: true, deep: true } } } </script>
- you can use vite plugin
- ❌ O02: for
Element-UI
, see also here[vite] Uncaught TypeError: Cannot read property '$isServer' of undefined at node_modules/[email protected]@element-ui/lib/utils/dom.js (:8080/node_modules/.vite/element-ui.js?v=675d2c77:1189) at __require (:8080/node_modules/.vite/chunk-6VNJZP5B.js?v=675d2c77:12) at node_modules/[email protected]@element-ui/lib/utils/popup/popup-manager.js (:8080/node_modules/.vite/element-ui.js?v=675d2c77:1478) at __require (:8080/node_modules/.vite/chunk-6VNJZP5B.js?v=675d2c77:12) at node_modules/[email protected]@element-ui/lib/utils/popup/index.js (:8080/node_modules/.vite/element-ui.js?v=675d2c77:1701) at __require (:8080/node_modules/.vite/chunk-6VNJZP5B.js?v=675d2c77:12) at node_modules/[email protected]@element-ui/lib/utils/vue-popper.js (:8080/node_modules/.vite/element-ui.js?v=675d2c77:2546) at __require (:8080/node_modules/.vite/chunk-6VNJZP5B.js?v=675d2c77:12) at Object.5 (:8080/node_modules/.vite/element-ui.js?v=675d2c77:6861) at __webpack_require__ (:8080/node_modules/.vite/element-ui.js?v=675d2c77:6547)
- ⚠️ O03: imports that containing multiple alias like:
@import '~@/styles/global.scss'
, which includes alias~
and@
at the same time- you can add an alias
{ find: /^~@/, replacement: path.resolve(__dirname, 'src') }
toresolve.alias
options, and place it as the first alias configuration
- you can add an alias
- ⚠️ O04: for
jsx
syntax in.vue
file- you need to enable
jsx
support : In Vue2, add pluginvite-plugin-vue2
and set{ jsx: true }
option. In Vue3, add plugin@vitejs/plugin-vue-jsx
- you also need to add attribute
lang="jsx"
toscript
label if jsx syntax is used, e.g.<script lang="jsx"></script>
- If you encountered the following error
you can try to update configuration of3:54:29 PM [vite] Internal server error: /Users/Chieffo/Documents/project/Vue-mmPlayer/src/base/mm-icon/mm-icon.vue?vue&type=script&lang.tsx: Duplicate declaration "h" (This is an error on an internal node. Probably an internal error.) Plugin: vite-plugin-vue2 File: /Users/Chieffo/Documents/project/Vue-mmPlayer/src/base/mm-icon/mm-icon.vue?vue&type=script&lang.tsx at File.buildCodeFrameError (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/core/lib/transformation/file/file.js:244:12) at Scope.checkBlockScopedCollisions (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/scope/index.js:421:22) at Scope.registerBinding (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/scope/index.js:581:16) at Scope.registerDeclaration (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/scope/index.js:523:14) at Object.BlockScoped (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/scope/index.js:240:12) at Object.newFn (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/visitors.js:212:17) at NodePath._call (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/path/context.js:53:20) at NodePath.call (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/path/context.js:36:14) at NodePath.visit (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/path/context.js:90:31) at TraversalContext.visitQueue (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/context.js:99:16) at TraversalContext.visitMultiple (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/context.js:68:17) at TraversalContext.visit (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/context.js:125:19) at Function.traverse.node (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/index.js:76:17) at NodePath.visit (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/path/context.js:97:18) at TraversalContext.visitQueue (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/context.js:99:16) at TraversalContext.visitSingle (/Users/Chieffo/Documents/project/Vue-mmPlayer/node_modules/@babel/traverse/lib/context.js:73:19)
babel.config.js
like this :
->module.exports = { presets: [ '@vue/app' ] }
see also heremodule.exports = { presets: [ ['@vue/babel-preset-jsx'] ] }
- you need to enable
- ⚠️ O05: for webpack syntax
require.context
- add vite plugin
@originjs/vite-plugin-require-context
, see also here
- add vite plugin
- ✅ O06: we have fixed the error
Compiling error when the template of the .vue file has the attribute lang="html"
- we will remove
lang="html"
attribute fromtemplate
label by default, see also here
- we will remove
- ❌ O07: webpack syntax
require.ensure
is not supported - ⚠️ O08: you need to convert
dynamic imports
that include alias toabsolute paths
orrelative paths
like the followings, see also here
->() => import('@/components/views/test.vue')
() => import('./components/views/test.vue')
- ⚠️ O09: if you encountered build error
[rollup-plugin-dynamic-import-variables] Unexpected token
, you need to remove empty attrsrcset
orsrcset=""
in<img>
label. - ⚠️ O10: Vite can't resolve some static asset, e.g.
.PNG
, you can put it inassetsInclude
option likeassetsInclude: ['**.PNG']
- ⚠️ O11: support
.md
markdown file as vue component, you need to addvite-plugin-md
plugin. - ⚠️ O12: The error
Uncaught ReferenceError: global is not defined
, see also hereFor reference, if you only need to shim global, you can add
<script>window.global = window;</script>
to yourindex.html
- ⚠️ O13: Support load SVG files as Vue components
- ... or when the following error is encountered
Uncaught (in promise) DOMException: Failed to execute 'createElement' on 'Document': The tag name provided ('/@fs/D:/project/example/node_modules/@example/example.svg') is not a valid name.
- add
vite-svg-loader
plugin for vue project - add
vite-plugin-svgr
plugin for react project
- ⚠️ O14: Fix the following errors
[Vue warn]: Component provided template option but runtime compilation is not supported in this build of Vue. Configure your bundler to alias "vue" to "vue/dist/vue.esm-bundler.js".
- you need to set the alias as follows
resolve: { alias: [ { find: 'vue', replacement: 'vue/dist/vue.esm-bundler.js' } ] }
- ⚠️ O15: You may need to install the
vite-plugin-optimize-persist
plugin for the following reasonsVite's dependencies pre-optimization is cool and can improve the DX a lot. While Vite can smartly detect dynamic dependencies, it's on-demanded natural sometimes make the booting up for complex project quite slow.
[vite] new dependencies found: @material-ui/icons/Dehaze, @material-ui/core/Box, @material-ui/core/Checkbox, updating... [vite] ✨ dependencies updated, reloading page... [vite] new dependencies found: @material-ui/core/Dialog, @material-ui/core/DialogActions, updating... [vite] ✨ dependencies updated, reloading page... [vite] new dependencies found: @material-ui/core/Accordion, @material-ui/core/AccordionSummary, updating... [vite] ✨ dependencies updated, reloading page...