>  기사  >  웹 프론트엔드  >  Vue 원격 코드를 로드하는 구성 요소 공유

Vue 원격 코드를 로드하는 구성 요소 공유

小云云
小云云원래의
2018-01-16 10:46:392482검색

vue 프로젝트(특히 백엔드 시스템)에는 동일한 프로젝트를 공동으로 개발하기 위해 여러 비즈니스 라인이 필요한 몇 가지 시나리오가 항상 있습니다. 각 비즈니스 팀이 프레임워크에 일부 전용 디스플레이 구성 요소를 제공하는 경우 이러한 구성 요소는 프라이빗 모듈의 잦은 변경으로 인해 프레임워크를 반복적으로 빌드하고 릴리스할 수 없기 때문에 프레임워크를 함께 패키지화합니다. 이 시나리오에서는 이러한 구성 요소를 프레임워크에 로드하는 것을 완료하기 위해 원격 비동기 코드를 로드하는 구성 요소가 필요합니다.

vue-cli는 Vue가 공식적으로 권장하는 프로젝트 구축 스캐폴딩입니다. 핫 리로딩, 빌드, 디버깅, 단위 테스트, 코드 감지 및 기타 기능과 같이 개발 프로세스에서 일반적으로 사용되는 기능을 제공합니다. 이번에는 vue-cli를 기반으로 비동기 원격 컴포넌트를 개발하겠습니다.

요구사항 분석

  1. 원격 코드를 로드하는 방법

  2. 로드된 코드를 프레임워크에 등록하는 방법입니다.

  3. 상위 구성 요소가 원격으로 도입된 구성 요소와 통신하는 방법입니다.

  4. 원격 코드가 프레임워크에 도입된 라이브러리를 재사용하는 방법.

  5. v-for처럼 원격 코드가 여러 번 호출되어 불필요한 요청을 피하세요.

원격 코드 로드

원격 코드는 접근 가능한 URL에 저장되어야 합니다. 그래야 소스 코드를 얻기 위해 Axios와 같은 HTTP 클라이언트를 통해 이 링크를 요청할 수 있습니다.

import Axios from 'axios';
export default {
 name: 'SyncComponent',
 props: {
  // 父组件提供请求地址
  url: {
   type: String,
   default: ''
  }
 },
 data() {
  return {
   resData: ''
  };
 },
 async mounted() {
  if (!this.url) return;
  const res = await Axios.get(this.url); // 我们在组件挂载完成时,请求远端代码并存储结果。
  this.resData = res.data;
 }
};

위는 편의상 기본 코드이며, 다음 예시에서는 반복되는 코드 부분을 생략하겠습니다.

프레임워크에 코드 등록

이 부분은 약간 번거롭고 여러 가지 문제가 있습니다.

브라우저는 .vue 템플릿 또는 ES.next 구문을 지원하지 않으며 모듈을 사용하려면 먼저 컴파일해야 합니다.

이 부분을 다루는 것은 상대적으로 간단합니다. 이러한 템플릿을 패키징하기 위해 webpack 구성 파일을 직접 정의합니다.

// 在 build 目录下新建 webpack.sync-components.prod.conf.js 文件
const webpack = require('webpack');
const path = require('path');
const utils = require('./utils');
const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin')
function resolve(dir) {
 return path.join(__dirname, '..', dir)
}
module.exports = {
 // 此处引入要打包的组件
 entry: {
  componentA: resolve('/src/views/component-a.vue')
 },
 // 输出到静态目录下
 output: {
  path: resolve('/static/'),
  filename: '[name].js',
 },
 resolve: {
  extensions: ['.js', '.vue', '.json'],
  alias: {
   'vue$': 'vue/dist/vue.esm.js',
   '@': resolve('src'),
  }
 },
 module: {
  rules: [
   {
    test: /\.vue$/,
    loader: 'vue-loader',
    options: {
     esModule: false, // ****** vue-loader v13 更新 默认值为 true v12及之前版本为 false, 此项配置影响 vue 自身异步组件写法以及 webpack 打包结果
     loaders: utils.cssLoaders({
      sourceMap: true,
      extract: false     // css 不做提取
     }),
     transformToRequire: {
      video: 'src',
      source: 'src',
      img: 'src',
      image: 'xlink:href'
     }
    }
   },
   {
    test: /\.js$/,
    loader: 'babel-loader',
    include: [resolve('src'), resolve('test')]
   },
   {
    test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
    loader: 'url-loader',
    options: {
     limit: 10000,
     name: utils.assetsPath('img/[name].[hash:7].[ext]')
    }
   },
   {
    test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
    loader: 'url-loader',
    options: {
     limit: 10000,
     name: utils.assetsPath('media/[name].[hash:7].[ext]')
    }
   },
   {
    test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
    loader: 'url-loader',
    options: {
     limit: 10000,
     name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
    }
   }
  ]
 },
 plugins: [
  new webpack.DefinePlugin({
   'process.env.NODE_ENV': '"production"'
  }),
  // 压缩JS
  new webpack.optimize.UglifyJsPlugin({
   compress: false,
   sourceMap: true
  }),
  // 压缩CSS 注意不做提取
  new OptimizeCSSPlugin({
   cssProcessorOptions: {
    safe: true
   }
  })
 ]
};

이 시점에서 우리 모듈은 프레임워크에서 인식할 수 있는 파일로 컴파일되었습니다.

1. 문자열을 js 객체로 변환하는 방법.

new Function。
async mounted() {
 if (!this.url) return;
 const res = await Axios.get(this.url);
 let Fn = Function;
 this.mode = new Fn(`return ${res.data}`)();
}

1. 변환된 js 객체를 vue에서 인식할 수 없습니다.

이 문제를 일으킬 수 있는 두 가지 가능성은 다음과 같습니다.

// vue-loader v13 esModule 更新 默认值为 true, v12及之前版本为 false, 此项配置影响 vue 自身异步组件写法以及 webpack 打包结果
{
 test: /\.vue$/,
 loader: 'vue-loader',
 options: {
  esModule: false
  ... 以下省略千军万码
 }
}
// UglifyJs 需要取消变量名替换配置,此配置并不会极大影响压缩率
new webpack.optimize.UglifyJsPlugin({
 compress: false,
 sourceMap: true
})

이 시점에서 원격 구성 요소가 프레임워크에 도입되었습니다.

상위 구성 요소가 원격으로 가져온 구성 요소와 어떻게 통신합니까? 여기에 문제가 있습니다. 뷰 구성 요소에서 원격 비동기 로딩 구성 요소, 중간 계층 원격 비동기 구성 요소까지의 통신 ​​계층이 있습니다. 공용 구성 요소로 수정되어야 합니다. 실제 비즈니스 구성 요소와 직접 통신하려면 보기 구성 요소가 필요합니다. vuex 및 eventBus 솔루션은 모두 너무 번거롭습니다. 여기서는 "fallthrough"(vue 구성 요소의 교차 레벨 통신)를 달성하기 위해 $attrs 및 $listeners(vue v2.4+)를 사용합니다.

// 修改 sync-component.vue 组件
// 新增 v-bind="$attrs" v-on="$listeners"
<component
 :is="mode"
 v-bind="$attrs"
 v-on="$listeners">
</component>
// inheritAttrs: true
export default {
 name: 'SyncComponent',
 props: {
  // 父组件提供请求地址
  url: {
   type: String,
   default: ''
  }
 },
 inheritAttrs: true
 ... 以下省略千军万码
}

원격 코드가 프레임워크에 도입된 라이브러리를 재사용하는 방법

우리는 원격 구성 요소 및 프레임워크에 더 큰 라이브러리나 플러그인이 반복적으로 도입되는 것을 보고 싶지 않습니다. 실제 단계. 주요 아이디어는 Vue.prototype.$xxx 컴포넌트의 공개 재사용을 실현하기 위해 공용 라이브러리를 Vue 프로토타입 체인에 마운트하는 것입니다.

// 全局添加 axios 对象
import axios from 'axios';
Vue.prototype.$http = axios;

에서 소개하는 원격 컴포넌트는 프레임워크 내에서 public 패키지에 접근할 수 있습니다. 이때 원격 컴포넌트를 패키징할 때 public 패키지의 코드가 포함되지 않도록 webpack도 구성해야 합니다.

// webpack.sync-components.prod.conf.js 添加
externals: {
 vue: 'vue',
 'element-ui': 'element-ui',
 axios: 'axios'
}

v-for처럼 원격 코드가 여러 번 호출되어 불필요한 요청을 피하세요.

이 부분에서는 전역 변수를 사전으로 직접 사용하여 하위 항목으로 요청 주소: 데이터가 포함된 배열을 저장합니다.

async mounted() {
 if (!this.url) return;
 // Cache 缓存 根据 url 参数
 if (!window.SyncComponentCache) {
  window.SyncComponentCache = {};
 }
 let res;
 if (!window.SyncComponentCache[this.url]) {
  window.SyncComponentCache[this.url] = Axios.get(this.url);
  res = await window.SyncComponentCache[this.url];
 } else {
  res = await window.SyncComponentCache[this.url];
 }
 let Fn = Function;
 this.mode = new Fn(`return ${res.data}`)();
 console.log(this.mode);
}

이 시점에서 비동기 원격 구성 요소를 로드하고 프레임워크와 통신할 수 있습니다.

이 기사의 소스 코드를 얻으려면 github를 방문하세요. 구성 요소는 NPM에 게시되었으며 직접 설치할 수 있습니다.


관련 권장 사항:


PHP가 원격 코드 예제를 읽거나 가져오는 방법에 대한 자세한 설명

ajax가 원격 통신을 구현합니다.

원격 파일의 존재를 판단하는 PHP 예제 공유

위 내용은 Vue 원격 코드를 로드하는 구성 요소 공유의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.