npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@originjs/webpack-to-vite

v1.2.0

Published

convert a webpack project to a vite project

Downloads

84

Readme

English | 简体中文

Test

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

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
  • ✅ B02: add vite's entry file index.html to root directory
    • multiple entries defined by the pages option in vue.config.js is supported
    • please add entry point like <script type="module" src="/src/main.js"></script>. There's no need to add dev-client entry point cause vite supports HMR by default
  • ✅ 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 enable jsx support by default
    • necessary for Vue3: @vitejs/plugin-vue, @vitejs/plugin-vue-jsx
  • ✅ B05: imports that omit .vue extension is supported
  • ✅ B06: sass is supported
    • if node-sass is used in dependency, then we'll convert it to sass to dependencies
  • ✅ B07: postcss 8 is supported
    • if postcss 8 is used, then we'll add postcss to dependencies
  • ⚠️ 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
  • ✅ 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 from html-webpack-plugin and use it like this:
    plugins: [
      createHtmlPlugin({
        inject: {
          data: {
            title: value,
          },
        },
        minify: {
          minifyCss: true
        }
      })
    ]
  • ⚠️ 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 to vite.config.js

  • ✅ V01: base public path

    • process.env.PUBLIC_URL or publicPath or baseUrl -> base
  • ✅ V02: css options

    • css.loaderOptions -> css.preprocessorOptions
    • css.loaderOptions.less.lessOptions.modifyVars -> css.preprocessorOptions.less.modifyVars
    • The sass configuration will influence both sass and scss in Vue-CLI, but in vite we need to configure them respectively. So with only css.loaderOptions.sass option is set in Vue-CLI, it will be converted to css.preprocessorOptions.sass and css.preprocessorOptions.scss. On the other hand, with only css.loaderOptions.scss option is set in Vue-CLI, it will be converted to css.preprocessorOptions.scss.
  • ✅ V03: server options

    • server.strictPort = false is set by default
    • process.env.PORT or devServer.port -> server.port
    • process.env.DEV_HOST or devServer.public or devServer.host -> server.host, and convert http:// or https:// to ''
    • devServer.open, devServer.https -> server.open, server.https
    • if devServer.proxy -> server.proxy is transformed in proxy configuration, we'll also pathRewrite -> rewrite
  • ✅ V04: build options

    • outputDir -> build.outDir
    • css.extract -> build.cssCodeSplit
    • if process.env.MODERN === 'true' is set, we'll also set build.minify = esbuild
    • process.env.GENERATE_SOURCEMAP === 'true' or vueConfig.productionSourceMap or css.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 to css.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";`
        }
      }
    }
  • ✅ V08: transform functional webpack config

    • The webpackConfigure and chainWebpack options could be defined as object or function in vue.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 reconfig html-webpack-plugin

Webpack conversion

Webpack conversion is based on webpack.config.js or webpack.base.js/webpack.dev.js/webpack.prod.js or webpack.build.js/webpack.production.js, map configuration to vite.config.js

Note: if you are not using configuration files above, you need to convert configurations manually

  • ✅ W01: build entry options
    • if entry is string type: entry -> build.rollupOptions.input
    • if entry is object type: the properties of entry will be converted set to build.rollupOptions.input
    • if entry is function type: execute result of entry will be set to build.rollupOptions.input
  • ✅ W02: output options
    • output.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
    1. use Web API new URL
    <template>
    <img alt="" :src="imgSrc" />
    </template>
    <script>
    export default {
    name: 'img',
    data: () => ({
      imgSrc: new URL('./assets/logo.png', import.meta.url).href
    })
    }
    </script>
    ...or use Vite's API import.meta.glob
    1. 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 })
          }
        }
      }
    })
    1. 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>
  • ❌ 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') } to resolve.alias options, and place it as the first alias configuration
  • ⚠️ O04: for jsx syntax in .vue file
    • you need to enable jsx support : In Vue2, add plugin vite-plugin-vue2 and set { jsx: true } option. In Vue3, add plugin @vitejs/plugin-vue-jsx
    • you also need to add attribute lang="jsx" to script label if jsx syntax is used, e.g. <script lang="jsx"></script>
    • If you encountered the following error
    3: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)
    you can try to update configuration of babel.config.js like this :
    module.exports = {
      presets: [
        '@vue/app'
      ]
    }
    ->
    module.exports = {
      presets: [
        ['@vue/babel-preset-jsx']
      ]
    }
    see also here
  • ⚠️ O05: for webpack syntax require.context
    • add vite plugin @originjs/vite-plugin-require-context, see also here
  • ✅ 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 from template label by default, see also here
  • ❌ O07: webpack syntax require.ensure is not supported
  • ⚠️ O08: you need to convert dynamic imports that include alias to absolute paths or relative 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 attr srcset or srcset="" in <img> label.
  • ⚠️ O10: Vite can't resolve some static asset, e.g. .PNG, you can put it in assetsInclude option like assetsInclude: ['**.PNG']
  • ⚠️ O11: support .md markdown file as vue component, you need to add vite-plugin-md plugin.
  • ⚠️ O12: The error Uncaught ReferenceError: global is not defined, see also here
    • For reference, if you only need to shim global, you can add <script>window.global = window;</script> to your index.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.
  • ⚠️ 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 reasons

    Vite'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...