详细记录前端项目使用import懒加载组件打包失败的踩坑之路

13 篇文章 0 订阅
2 篇文章 0 订阅

前言:

有些问题真的很玄学,但是出现了你又不得不去解决,哪怕解决完了你还是一脸懵逼,但是解决一次也算累积了一次经验了。

这篇笔记是基于之前的一篇笔记的补充加强版:所以看下去之前建议先移步之前那篇笔记:

关于vue 动态引入(异步加载import和require)组件的方法和坑(按需懒加载组件,动态生成路由)babel-plugin-dynamic-import-node 优化编译速度

由于前几天又遇到一个神坑,所以有了这篇加强版的笔记:

先说说坑:

前端根据后端授权的菜单数据动态生成前端路由地图的时候,一般我们会采用import懒加载的方式来加载路由对应的组件:

return () => import(/* webpackChunkName: "[request]" */ `@/views/${view}`)

本来打包一直都好好的,突然有一次因为某个功能需要安装某个依赖包,然后再执行打包的时候,就不行了。import懒加载的组件路由,访问页面的时候都找不到对应的模块。检查一下才看到,build虽然没有报错,但是生成的dist目录下并没那些懒加载组件对应js文件。

问题原因很明显,就是使用import懒加载组件出了问题。

刨坑:

第一时间怀疑是安装的包导致了webpack版本降低了,因为webpack低版本是不支持import的,所以查了webpack版本,4.x,所以不是它的问题。

然后又重新删了引入的包,还是不行;

再次把node_modules删了,依赖重装,还是不行;
然后想起来之前写过一篇关于组件懒加载的博文章,就是文章开头的那个链接。

当然,无非就是让import组件在打包的时候能够被正确转换成reqiure, 所说需要额外的插件和babel配置(但是之前正常,babel配置没动过,按道理不该怀疑它,但是没办法,问题总要解决)。


安装并在babel配置文件中配置,@/babel/plugin-syntax-dynamic-import,这个依赖就是干这事的。

不过,只需要在babel.config.js文件中配置这个就行了:@babel/preset-env。因为它已经包括了@/babel/plugin-syntax-dynamic-import依赖。


但是做完这些都还不行,我就懵了。因为之前也这么解决过这个问题。


然后又是各种捣鼓,什么招都使了,还是不行。

最后还是回到babel.config.js文件,尝试把这个配置删了'@vue/cli-plugin-babel/preset',奇迹出现了,果然成了。


我为什么会配置@vue/cli-plugin-babel/preset这个?是因为之前别的项目也同时配置了它和@babel/preset-env,import都能正常使用,但是放到这个项目就不行了,所以就很服气。

但正常理解这个预设@vue/cli-plugin-babel/preset其实@babel/preset-env并不冲突,两个预设的功能有重叠,大部分就是把es6的新语法进行转换,和转换vue代码。

而且@vue/cli-plugin-babel/preset这个预设还包含了比如jsx代码的转换,如果你的代码里使用了jsx,配置这个预设就能解决。

但是现在加了这个预设,打包还是有问题,所以只能删了他,仅保存@babel/preset-env这个预设,再单独配置这个依赖:'@vue/babel-preset-jsx', 这样就正常了。

虽然整个过程还是有些懵,好在最后,是搞定了,也不担心安装新依赖的问题了。


但是这个问题出现的根本原因是啥,我还是没搞明白,为什么随便安装了一个其他依赖,import突然就不行了?

而且之前babel配置文件里也没有配置@babel/preset-env这个或@/babel/plugin-syntax-dynamic-import,怎么impport懒加载组件都是没问题的?

然后突然就不行了,需要补充配置import转require的bable配置,不知道有没有大神来解答一下。
最后附上babel的配置:

module.exports = {
  presets: [
    '@vue/babel-preset-jsx',
    [
      '@babel/preset-env',
      {
        'useBuiltIns': 'entry',
        'corejs': 3
      }
    ]
  ],
  'env': {
    'development': {
      'plugins': ['dynamic-import-node']
    }
  }
}

再附上一个比较全的babel.config.js配置,这个是chatgpt3.5生成的,是否之前待验证:

module.exports = {
  presets: [
    // 预设,用于指定babel转换代码的规则和插件
    '@babel/preset-react', // 将JSX语法转换为React.createElement函数调用
    [
      '@babel/preset-env', // 将ES6+代码转换为向后兼容的代码
      {
        // useBuiltIns选项指定如何处理ES6中的新特性,例如Promise和Map。'entry'表示根据需要自动引入polyfill,'usage'表示根据代码中使用的特性自动引入polyfill。
        useBuiltIns: 'entry',
        // corejs选项指定使用的core-js版本。
        corejs: 3,
        // targets选项指定需要支持的浏览器或Node.js版本。
        targets: {
          // 可以使用字符串或对象指定目标环境。
          chrome: '58',
          firefox: '54',
          safari: '11',
          edge: '16',
          node: '8'
        },
        // modules选项指定如何处理模块化代码。'auto'表示根据目标环境自动选择,'commonjs'表示转换为CommonJS模块,'false'表示不转换。
        modules: 'auto',
        // debug选项用于输出Babel的调试信息。
        debug: true,
        // include选项用于指定需要转换的文件路径。
        include: [],
        // exclude选项用于指定不需要转换的文件路径。
        exclude: [],
        // loose选项用于指定是否使用松散模式转换代码。
        loose: true,
        // shippedProposals选项用于指定是否支持实验性语法。
        shippedProposals: true,
        // forceAllTransforms选项用于强制转换所有代码,即使目标环境已经支持该特性。
        forceAllTransforms: true,
        // ignoreBrowserslistConfig选项用于忽略.browserslistrc文件中的配置。
        ignoreBrowserslistConfig: true,
        // configPath选项用于指定.babelrc文件的路径。
        configPath: './.babelrc'
      }
    ],
    // @vue/cli-plugin-babel/preset是Vue CLI的Babel预设,用于转换Vue.js代码。
    '@vue/cli-plugin-babel/preset',
    // @vue/babel-preset-jsx是Vue.js的JSX预设,用于转换Vue.js中的JSX代码。
    '@vue/babel-preset-jsx'
  ],
  plugins: [
    // 插件,用于扩展babel的功能
    '@babel/plugin-transform-runtime', // 将代码中的公共部分提取到单独的模块中,避免重复打包
    '@babel/plugin-proposal-class-properties' // 支持类属性的语法
  ],
  env: {
    // 环境配置,用于指定不同的环境下的babel配置
    development: {
      presets: [
        '@babel/preset-env',
        '@babel/preset-react'
      ],
      plugins: [
        'dynamic-import-node'
        '@babel/plugin-transform-runtime',
        '@babel/plugin-proposal-class-properties'
      ]
    },
    production: {
      presets: [
        ['@babel/preset-env', { modules: false }], // 将ES6+代码转换为向后兼容的代码,同时禁用模块转换,交由打包工具处理
        '@babel/preset-react'
      ],
      plugins: [
        'uglifyjs-webpack-plugin',
        '@babel/plugin-transform-runtime',
        '@babel/plugin-proposal-class-properties'
      ]
    }
  },
  ignore: [
    // 忽略文件,用于指定babel忽略哪些文件
    '*.test.js', // 忽略测试文件
    'node_modules' // 忽略node_modules目录下的文件
  ],
  overrides: [
    // 覆盖配置,用于指定特定文件的babel配置
    {
      test: /\.jsx$/, // 匹配所有以.jsx结尾的文件
      presets: ['@babel/preset-react'] // 指定只使用@babel/preset-react预设
    }
  ],
  sourceType: 'module', // 源代码类型,用于指定babel解析的代码类型
  compact: true, // 是否压缩代码
  minified: true, // 是否最小化代码
  comments: false, // 是否保留注释
  retainLines: true, // 是否保留代码行数
  sourceMaps: true, // 是否生成source map
  babelrc: false, // 是否使用.babelrc文件
  configFile: false, // 是否使用babel.config文件
  passPerPreset: true, // 是否将每个预设的结果传递给下一个预设
  cwd: process.cwd(), // 当前工作目录
  root: process.cwd(), // 项目根目录
  rootMode: 'root', // 项目根模式
  envName: process.env.NODE_ENV // 当前环境名称
};

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
在Vue函数里使用`import`加载组件,需要注意以下几点: 1. 因为`import`是异步加载模块的方式,所以需要使用`async/await`或者`Promise`来处理异步加载的结果。 2. 在Vue函数里,组件需要先注册再使用。因此,在使用`import`加载组件之前,需要先使用`Vue.component`方法注册该组件。 下面是一个示例代码: ``` import Vue from 'vue' import ComponentA from './components/ComponentA.vue' import ComponentB from './components/ComponentB.vue' // 先注册组件 Vue.component('ComponentA', ComponentA) Vue.component('ComponentB', ComponentB) // Vue函数 new Vue({ el: '#app', data: { currentComponent: 'ComponentA' }, methods: { async loadComponentB() { // 使用async/await方式加载组件 const { default: ComponentB } = await import('./components/ComponentB.vue') Vue.component('ComponentB', ComponentB) this.currentComponent = 'ComponentB' }, loadComponentC() { // 使用Promise方式加载组件 import('./components/ComponentC.vue').then(({ default: ComponentC }) => { Vue.component('ComponentC', ComponentC) this.currentComponent = 'ComponentC' }) } } }) ``` 在上面的示例代码中,首先使用`Vue.component`方法注册了`ComponentA`和`ComponentB`两个组件。然后,在`loadComponentB`方法中,使用`async/await`方式加载`ComponentB`组件,并注册该组件;在`loadComponentC`方法中,使用`Promise`方式加载`ComponentC`组件,并注册该组件。最后,通过修改`currentComponent`的值来动态显示不同的组件

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值