advanced-cropper / vue-advanced-cropper

The advanced vue cropper library that gives you opportunity to create your own croppers suited for any website design
https://advanced-cropper.github.io/vue-advanced-cropper/
Other
930 stars 128 forks source link

Cropper doesn't work after deployment. #250

Closed dreamsea503 closed 9 months ago

dreamsea503 commented 9 months ago

Observed Behavior

On my localhost, cropper works well but it doesn't work after deployment with following error. I don't understand why this is happening. This may be related to my deployment configuration values with conflicts?

image

Versions

vue-advanced-cropper: v2.8.8 vue: v3.2.45 webpack: v5.88.2

These are my webpack configurations

{
  resolve: {
    extensions: ['*', '.js', '.vue', '.json'],
    alias: {
      '@': resolve('web'),
      '@modals': resolve('web', 'components', 'modals'),
      '@cards': resolve('web', 'components', 'cards'),
      '@abstract': resolve('web', 'components', 'abstract'),
      '~': resolve() //root
    },
  },
  mode: 'production'
}
Norserium commented 9 months ago

@shiningsea0415, please provide the source code where you use the cropper.

dreamsea503 commented 9 months ago

Sure.

Here are my cropper components that I used in my project.

This is main cropper component.

<template>
  <div style="width: 100%; min-height:200px">
    <Cropper
      ref="cropper"
      :src="image"
      :style="cropperStyle"
      :stencil-component="Stencil"
      :stencil-props="{aspectRatio}"
      :canvas="{maxWidth: 400, maxHeight: 400}" />
  </div>
</template>

<script>
export default {name: 'VueCropper'};
</script>

<script setup>
import {computed, defineExpose, defineProps, ref} from 'vue';
import {Cropper} from 'vue-advanced-cropper';
import Stencil from './Stencil';
import 'vue-advanced-cropper/dist/style.css';

// Props
const props = defineProps({
  image: {
    type: String,
    default: ''
  },
  width: {
    type: String,
    default: '375px'
  }
});

// Refs
const cropper = ref(null);
const aspectRatio = ref(1);

// Uses vue advance cropper function to get the cropped results
function getResult() {
  return cropper.value.getResult();
}

// Exposes vue advanced cropper's function to parent component
defineExpose({getResult});

// Computed
const cropperStyle = computed(() => {
  return `width: ${props.width}`;
});
</script>

This is Stencil component.

<template>
  <div
    class="circle-stencil"
    :style="style">
    <DraggableElement
      class="circle-stencil__handler"
      @drag="onResize"
      @drag-end="onResizeEnd">
      <q-icon
        size="20px"
        color="white"
        name="fas fa-expand-alt" />
    </DraggableElement>
    <DraggableArea
      @move="onMove"
      @move-end="onMoveEnd">
      <stencil-preview
        class="circle-stencil__preview"
        :image="image"
        :coordinates="coordinates"
        :transitions="transitions"
        :width="stencilCoordinates.width"
        :height="stencilCoordinates.height" />
    </DraggableArea>
  </div>
</template>

<script>
export default {name: 'CustomStencil'};
</script>

<script setup>
import {computed, defineEmits, defineProps} from 'vue';
import {
  DraggableArea,
  DraggableElement,
  ResizeEvent,
  StencilPreview
} from 'vue-advanced-cropper';

// Props
const props = defineProps({
  image: {
    type: Object,
    default: () => {}
  },
  coordinates: {
    type: Object,
    default: () => {}
  },
  transitions: {
    type: Object,
    default: () => {}
  },
  stencilCoordinates: {
    type: Object,
    default: () => {}
  }
});

// Emits
const emit = defineEmits([
  'move', 'move-end', 'resize', 'resize-end'
]);

// Computed
const style = computed(() => {
  const {height, width, left, top} = props.stencilCoordinates;
  const style = {
    width: `${width}px`,
    height: `${height}px`,
    transform: `translate(${left}px, ${top}px)`
  };

  if(props.transitions && props.transitions.enabled) {
    const {time, timingFunction} = props.transitions;
    style.transition = `${time}ms ${timingFunction}`;
  }
  return style;
});

// Helper functions
function onMove(moveEvent) {
  emit('move', moveEvent);
}

function onMoveEnd() {
  emit('move-end');
}

function onResize(dragEvent) {
  const shift = dragEvent.shift();
  const widthResize = shift.left;
  const heightResize = -shift.top;
  emit(
    'resize',
    new ResizeEvent(
      {
        left: widthResize,
        right: widthResize,
        top: heightResize,
        bottom: heightResize
      },
      {compensate: true}
    )
  );
}

function onResizeEnd() {
  emit('resize-end');
}
</script>

<style lang="scss">
.circle-stencil {
  cursor: move;
  position: absolute;
  border-radius: 50%;
  box-sizing: border-box;
  border: dashed 2px white;
  &__handler {
    position: absolute;
    top: 14%;
    right: 15%;
    z-index: 1;
    width: 30px;
    height: 30px;
    display: flex;
    cursor: ne-resize;
    align-items: center;
    justify-content: center;
    transform: translate(50%, -50%);
  }
  &__preview {
    overflow: hidden;
    border-radius: 50%;
  }
}
</style>
Norserium commented 9 months ago

@shiningsea0415, when does this error happens? On load or a specific action?

Try to rename the variable cropper to cropperRef just for test:

// Refs
const cropper = ref(null);
const aspectRatio = ref(1);

// Uses vue advance cropper function to get the cropped results
function getResult() {
  return cropper.value.getResult();
}
dreamsea503 commented 9 months ago

There is a file picker button. Once I pick one image file, above cropper component is rendered. At this time I got this error with empty component.

Norserium commented 9 months ago

@shiningsea0415, did you try to rename the variable?

dreamsea503 commented 9 months ago

Yes, I just tried. Still same error.

dreamsea503 commented 9 months ago

Hi, Norserium.

Any updates?

Norserium commented 9 months ago

@shiningsea0415, could you send me the error message screenshot?

dreamsea503 commented 9 months ago

I posted it as image at first.

https://github.com/advanced-cropper/vue-advanced-cropper/issues/250#issue-1917901611

Norserium commented 9 months ago

@shiningsea0415, I know, but I want to see it after your change.

dreamsea503 commented 9 months ago

The same error.

Norserium commented 9 months ago

What was the name of variable? Was it cropper or cropperRef?

tolson4 commented 9 months ago

@Norserium I'm helping out @shiningsea0415 with this. I am able to reproduce and noticed that the error originates here https://github.com/advanced-cropper/vue-advanced-cropper/blob/master/src/Cropper.vue#L1337. For whatever reason, classes is showing up as undefined, and cropper can't be read from undefined.

I have updated the initial code block @shiningsea0415 posted to remove the ref entirely, instead relying on the change event to get the result.

<template>
  <div style="width: 100%; min-height:200px">
    <Cropper
      :src="image"
      :style="cropperStyle"
      :stencil-component="Stencil"
      :stencil-props="{aspectRatio}"
      :canvas="{maxWidth: 400, maxHeight: 400}"
      @change="setImage" />
  </div>
</template>

<script>
export default {name: 'VueCropper'};
</script>

<script setup>
import {computed, defineProps, ref} from 'vue';
import {Cropper} from 'vue-advanced-cropper';
import Stencil from './Stencil';
import 'vue-advanced-cropper/dist/style.css';

// Props
const props = defineProps({
  image: {
    type: String,
    default: ''
  },
  width: {
    type: String,
    default: '375px'
  }
});

// Refs
const aspectRatio = ref(1);
const croppedImage = ref('');

function setImage({canvas}) {
  const newImageUrl = canvas.toDataURL('image/jpeg');
  croppedImage.value = newImageUrl;
}

// Computed
const cropperStyle = computed(() => {
  return `width: ${props.width}`;
});
</script>

Even with these changes, the error still occurs and matches what was posted above: image

Norserium commented 9 months ago

@tolson4, it's interesting. It looks like the minification issue at the first glance. Could you disable it temporary?

tolson4 commented 9 months ago

Sure, heres the screenshot image

Norserium commented 9 months ago

@tolson4, could you send me the bundle file where the error happens to my email?

tolson4 commented 9 months ago

@Norserium I just set up a minimal example here that reproduces the issue.

Norserium commented 9 months ago

@tolson4, well, it took a while to investigate your issue and I may say that it is not directly related to this library. The problem here that the cropper uses Options API and to support it __VUE_OPTIONS_API__ should be enabled.

It's enabled by default as the developers said , but it's the half-truth, cause it doesn't have the default value for ESM-build:

__FEATURE_OPTIONS_API__: isBundlerESMBuild ? `__VUE_OPTIONS_API__`  : `true`,

So you need to replace __VUE_OPTIONS_API__ on true by yourself. To make it update your lib/webpack.js file in the following way:

import * as bedrock from '@bedrock/core';
import webpack from 'webpack';
import {resolve} from './utils.js';
const {config} = bedrock;

// WEBPACK CONFIGURATION
config['bedrock-webpack'].configs.push({
  resolve: {
    extensions: ['*', '.js', '.vue', '.json'],
    alias: {
      '@': resolve('web'),
      '~': resolve() //root
    },
  },
  mode: 'production',
  plugins: [
    new webpack.DefinePlugin({
      __VUE_OPTIONS_API__: true,
    }),
  ],
});
tolson4 commented 9 months ago

@Norserium That change has resolved our issue, thank you for the support!

Norserium commented 9 months ago

@tolson4, you are welcome!